@lucid-agents/taskmarket 1.17.0 → 1.17.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/agent-compatibility.json +1 -1
- package/dist/budget-view-XKZC3GY5.js +36 -0
- package/dist/channels-JF4Q5KG3.js +29 -0
- package/dist/chunk-52Q2DCZN.js +1099 -0
- package/dist/chunk-73RXOYME.js +185 -0
- package/dist/{chunk-3XPF2O6L.js → chunk-FRV3ZHUR.js} +5381 -6300
- package/dist/chunk-GJQUALXN.js +1062 -0
- package/dist/chunk-LDCFKFF6.js +154 -0
- package/dist/{compatibility-F3RC2GX7.js → chunk-OKZ2NRYZ.js} +5 -5
- package/dist/chunk-XXD7TWLP.js +181 -0
- package/dist/{chunk-O27J7ZPH.js → chunk-YM4S6IE4.js} +2 -1
- package/dist/compatibility-KUYGZSUC.js +19 -0
- package/dist/doctor-7TWLIJWW.js +216 -0
- package/dist/{errors-F3EGNA4F.js → errors-2L357HGA.js} +1 -1
- package/dist/index.js +317 -162
- package/dist/{launch-EZJGJJ5Y.js → launch-2U3KFTFD.js} +1414 -700
- package/dist/pi-extensions/remote-tools.cjs +103 -0
- package/dist/pi-extensions/xgate.cjs +310 -5
- package/dist/reconcile-XZR2UYSW.js +83 -0
- package/dist/status-5IMULBQQ.js +18 -0
- package/package.json +3 -3
|
@@ -1,22 +1,67 @@
|
|
|
1
1
|
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
2
2
|
import {
|
|
3
|
+
SANDBOX_TOOL_USER,
|
|
4
|
+
SandboxUnavailableError,
|
|
5
|
+
buyComputeChunk,
|
|
6
|
+
computeAllocationId,
|
|
7
|
+
computeCreditObserver,
|
|
8
|
+
computeCreditOffer,
|
|
9
|
+
openSandbox,
|
|
10
|
+
readComputeView
|
|
11
|
+
} from "./chunk-LDCFKFF6.js";
|
|
12
|
+
import {
|
|
13
|
+
applyComputeCreditSetup,
|
|
14
|
+
atomicToUsd,
|
|
15
|
+
buyComputeCredit,
|
|
16
|
+
fetchComputePricing,
|
|
17
|
+
loadComputeCreditConfig,
|
|
18
|
+
planComputeCreditSetup,
|
|
19
|
+
readComputeCreditBalance,
|
|
20
|
+
usdToAtomic
|
|
21
|
+
} from "./chunk-52Q2DCZN.js";
|
|
22
|
+
import {
|
|
23
|
+
MAX_RETIRED_RAILS,
|
|
24
|
+
WORKSPACE_CONSENT_VERSION,
|
|
25
|
+
XGATE_ROUTES,
|
|
26
|
+
XgateError,
|
|
27
|
+
XgatePurchaseError,
|
|
28
|
+
allocationViews,
|
|
29
|
+
assessAgentPolicy,
|
|
30
|
+
channelView,
|
|
31
|
+
createAgentTransport,
|
|
32
|
+
getAgentPolicyPath,
|
|
33
|
+
openAgentChannels,
|
|
34
|
+
readAgentPolicy,
|
|
35
|
+
reconcileLeftoverOperations,
|
|
36
|
+
routeOfCatalogRow,
|
|
37
|
+
saveAgentPolicy,
|
|
38
|
+
selectModels,
|
|
39
|
+
settledRetiredRails
|
|
40
|
+
} from "./chunk-GJQUALXN.js";
|
|
41
|
+
import {
|
|
42
|
+
BASE_CHANNEL_RAIL_ID,
|
|
3
43
|
apiUrl,
|
|
4
44
|
createBaseChannelPayer,
|
|
5
45
|
createBaseChannelRpcReader,
|
|
6
|
-
createWalletAccountFromKeystore,
|
|
7
46
|
createX402Allocations,
|
|
8
47
|
getTaskmarketHome,
|
|
9
48
|
getX402JournalPath,
|
|
10
49
|
getX402PolicyPath,
|
|
11
50
|
keystoreExists,
|
|
51
|
+
listX402Payments,
|
|
12
52
|
loadKeystore,
|
|
13
53
|
loadX402Policy,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
54
|
+
parseX402Policy,
|
|
55
|
+
saveX402Policy,
|
|
56
|
+
x402SpendWindowAvailability
|
|
57
|
+
} from "./chunk-FRV3ZHUR.js";
|
|
17
58
|
import {
|
|
18
59
|
AgentLaunchError
|
|
19
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-YM4S6IE4.js";
|
|
61
|
+
import {
|
|
62
|
+
AGENT_VIEW_VERSION,
|
|
63
|
+
formatUsdc
|
|
64
|
+
} from "./chunk-73RXOYME.js";
|
|
20
65
|
import {
|
|
21
66
|
__commonJS,
|
|
22
67
|
__require,
|
|
@@ -8080,11 +8125,11 @@ var require_agent = __commonJS({
|
|
|
8080
8125
|
};
|
|
8081
8126
|
})();
|
|
8082
8127
|
var WINDOWS_PIPE_REGEX = /^[/\\][/\\]\.[/\\]pipe[/\\].+/;
|
|
8083
|
-
function createAgent(
|
|
8084
|
-
if (process.platform === "win32" && !WINDOWS_PIPE_REGEX.test(
|
|
8085
|
-
return
|
|
8128
|
+
function createAgent(path6) {
|
|
8129
|
+
if (process.platform === "win32" && !WINDOWS_PIPE_REGEX.test(path6)) {
|
|
8130
|
+
return path6 === "pageant" ? new PageantAgent() : new CygwinAgent(path6);
|
|
8086
8131
|
}
|
|
8087
|
-
return new OpenSSHAgent(
|
|
8132
|
+
return new OpenSSHAgent(path6);
|
|
8088
8133
|
}
|
|
8089
8134
|
var AgentProtocol = (() => {
|
|
8090
8135
|
const SSH_AGENTC_REQUEST_IDENTITIES = 11;
|
|
@@ -8882,7 +8927,7 @@ var require_handlers_misc = __commonJS({
|
|
|
8882
8927
|
},
|
|
8883
8928
|
[MESSAGE.DEBUG]: (self2, payload) => {
|
|
8884
8929
|
bufferParser.init(payload, 1);
|
|
8885
|
-
const
|
|
8930
|
+
const display = bufferParser.readBool();
|
|
8886
8931
|
const msg = bufferParser.readString(true);
|
|
8887
8932
|
const lang = bufferParser.readString();
|
|
8888
8933
|
bufferParser.clear();
|
|
@@ -8894,7 +8939,7 @@ var require_handlers_misc = __commonJS({
|
|
|
8894
8939
|
}
|
|
8895
8940
|
self2._debug && self2._debug("Inbound: Received DEBUG");
|
|
8896
8941
|
const handler = self2._handlers.DEBUG;
|
|
8897
|
-
handler && handler(self2,
|
|
8942
|
+
handler && handler(self2, display, msg);
|
|
8898
8943
|
},
|
|
8899
8944
|
[MESSAGE.SERVICE_REQUEST]: (self2, payload) => {
|
|
8900
8945
|
bufferParser.init(payload, 1);
|
|
@@ -13328,17 +13373,17 @@ var require_SFTP = __commonJS({
|
|
|
13328
13373
|
// ===========================================================================
|
|
13329
13374
|
// Client-specific ===========================================================
|
|
13330
13375
|
// ===========================================================================
|
|
13331
|
-
createReadStream(
|
|
13376
|
+
createReadStream(path6, options) {
|
|
13332
13377
|
if (this.server)
|
|
13333
13378
|
throw new Error("Client-only method called in server mode");
|
|
13334
|
-
return new ReadStream(this,
|
|
13379
|
+
return new ReadStream(this, path6, options);
|
|
13335
13380
|
}
|
|
13336
|
-
createWriteStream(
|
|
13381
|
+
createWriteStream(path6, options) {
|
|
13337
13382
|
if (this.server)
|
|
13338
13383
|
throw new Error("Client-only method called in server mode");
|
|
13339
|
-
return new WriteStream(this,
|
|
13384
|
+
return new WriteStream(this, path6, options);
|
|
13340
13385
|
}
|
|
13341
|
-
open(
|
|
13386
|
+
open(path6, flags_, attrs, cb) {
|
|
13342
13387
|
if (this.server)
|
|
13343
13388
|
throw new Error("Client-only method called in server mode");
|
|
13344
13389
|
if (typeof attrs === "function") {
|
|
@@ -13357,7 +13402,7 @@ var require_SFTP = __commonJS({
|
|
|
13357
13402
|
attrsFlags = attrs.flags;
|
|
13358
13403
|
attrsLen = attrs.nb;
|
|
13359
13404
|
}
|
|
13360
|
-
const pathLen = Buffer.byteLength(
|
|
13405
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13361
13406
|
let p = 9;
|
|
13362
13407
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + 4 + attrsLen);
|
|
13363
13408
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13365,7 +13410,7 @@ var require_SFTP = __commonJS({
|
|
|
13365
13410
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13366
13411
|
writeUInt32BE(buf, reqid, 5);
|
|
13367
13412
|
writeUInt32BE(buf, pathLen, p);
|
|
13368
|
-
buf.utf8Write(
|
|
13413
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13369
13414
|
writeUInt32BE(buf, flags, p += pathLen);
|
|
13370
13415
|
writeUInt32BE(buf, attrsFlags, p += 4);
|
|
13371
13416
|
if (attrsLen) {
|
|
@@ -13496,7 +13541,7 @@ var require_SFTP = __commonJS({
|
|
|
13496
13541
|
throw new Error("Client-only method called in server mode");
|
|
13497
13542
|
fastXfer(fs3, this, localPath, remotePath, opts, cb);
|
|
13498
13543
|
}
|
|
13499
|
-
readFile(
|
|
13544
|
+
readFile(path6, options, callback_) {
|
|
13500
13545
|
if (this.server)
|
|
13501
13546
|
throw new Error("Client-only method called in server mode");
|
|
13502
13547
|
let callback;
|
|
@@ -13569,13 +13614,13 @@ var require_SFTP = __commonJS({
|
|
|
13569
13614
|
return callback && callback(er, buffer);
|
|
13570
13615
|
});
|
|
13571
13616
|
};
|
|
13572
|
-
this.open(
|
|
13617
|
+
this.open(path6, flag, 438, (er, handle_) => {
|
|
13573
13618
|
if (er)
|
|
13574
13619
|
return callback && callback(er);
|
|
13575
13620
|
handle = handle_;
|
|
13576
13621
|
const tryStat = (er2, st) => {
|
|
13577
13622
|
if (er2) {
|
|
13578
|
-
this.stat(
|
|
13623
|
+
this.stat(path6, (er_, st_) => {
|
|
13579
13624
|
if (er_) {
|
|
13580
13625
|
return this.close(handle, () => {
|
|
13581
13626
|
callback && callback(er2);
|
|
@@ -13596,7 +13641,7 @@ var require_SFTP = __commonJS({
|
|
|
13596
13641
|
this.fstat(handle, tryStat);
|
|
13597
13642
|
});
|
|
13598
13643
|
}
|
|
13599
|
-
writeFile(
|
|
13644
|
+
writeFile(path6, data, options, callback_) {
|
|
13600
13645
|
if (this.server)
|
|
13601
13646
|
throw new Error("Client-only method called in server mode");
|
|
13602
13647
|
let callback;
|
|
@@ -13615,7 +13660,7 @@ var require_SFTP = __commonJS({
|
|
|
13615
13660
|
if (options.encoding && !Buffer.isEncoding(options.encoding))
|
|
13616
13661
|
throw new Error(`Unknown encoding: ${options.encoding}`);
|
|
13617
13662
|
const flag = options.flag || "w";
|
|
13618
|
-
this.open(
|
|
13663
|
+
this.open(path6, flag, options.mode, (openErr, handle) => {
|
|
13619
13664
|
if (openErr) {
|
|
13620
13665
|
callback && callback(openErr);
|
|
13621
13666
|
} else {
|
|
@@ -13624,7 +13669,7 @@ var require_SFTP = __commonJS({
|
|
|
13624
13669
|
if (position === null) {
|
|
13625
13670
|
const tryStat = (er, st) => {
|
|
13626
13671
|
if (er) {
|
|
13627
|
-
this.stat(
|
|
13672
|
+
this.stat(path6, (er_, st_) => {
|
|
13628
13673
|
if (er_) {
|
|
13629
13674
|
return this.close(handle, () => {
|
|
13630
13675
|
callback && callback(er);
|
|
@@ -13643,7 +13688,7 @@ var require_SFTP = __commonJS({
|
|
|
13643
13688
|
}
|
|
13644
13689
|
});
|
|
13645
13690
|
}
|
|
13646
|
-
appendFile(
|
|
13691
|
+
appendFile(path6, data, options, callback_) {
|
|
13647
13692
|
if (this.server)
|
|
13648
13693
|
throw new Error("Client-only method called in server mode");
|
|
13649
13694
|
let callback;
|
|
@@ -13661,12 +13706,12 @@ var require_SFTP = __commonJS({
|
|
|
13661
13706
|
throw new TypeError("Bad arguments");
|
|
13662
13707
|
if (!options.flag)
|
|
13663
13708
|
options = Object.assign({ flag: "a" }, options);
|
|
13664
|
-
this.writeFile(
|
|
13709
|
+
this.writeFile(path6, data, options, callback);
|
|
13665
13710
|
}
|
|
13666
|
-
exists(
|
|
13711
|
+
exists(path6, cb) {
|
|
13667
13712
|
if (this.server)
|
|
13668
13713
|
throw new Error("Client-only method called in server mode");
|
|
13669
|
-
this.stat(
|
|
13714
|
+
this.stat(path6, (err) => {
|
|
13670
13715
|
cb && cb(err ? false : true);
|
|
13671
13716
|
});
|
|
13672
13717
|
}
|
|
@@ -13709,7 +13754,7 @@ var require_SFTP = __commonJS({
|
|
|
13709
13754
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} RENAME`
|
|
13710
13755
|
);
|
|
13711
13756
|
}
|
|
13712
|
-
mkdir(
|
|
13757
|
+
mkdir(path6, attrs, cb) {
|
|
13713
13758
|
if (this.server)
|
|
13714
13759
|
throw new Error("Client-only method called in server mode");
|
|
13715
13760
|
let flags = 0;
|
|
@@ -13723,7 +13768,7 @@ var require_SFTP = __commonJS({
|
|
|
13723
13768
|
flags = attrs.flags;
|
|
13724
13769
|
attrsLen = attrs.nb;
|
|
13725
13770
|
}
|
|
13726
|
-
const pathLen = Buffer.byteLength(
|
|
13771
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13727
13772
|
let p = 9;
|
|
13728
13773
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + attrsLen);
|
|
13729
13774
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13731,7 +13776,7 @@ var require_SFTP = __commonJS({
|
|
|
13731
13776
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13732
13777
|
writeUInt32BE(buf, reqid, 5);
|
|
13733
13778
|
writeUInt32BE(buf, pathLen, p);
|
|
13734
|
-
buf.utf8Write(
|
|
13779
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13735
13780
|
writeUInt32BE(buf, flags, p += pathLen);
|
|
13736
13781
|
if (attrsLen) {
|
|
13737
13782
|
p += 4;
|
|
@@ -13747,10 +13792,10 @@ var require_SFTP = __commonJS({
|
|
|
13747
13792
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} MKDIR`
|
|
13748
13793
|
);
|
|
13749
13794
|
}
|
|
13750
|
-
rmdir(
|
|
13795
|
+
rmdir(path6, cb) {
|
|
13751
13796
|
if (this.server)
|
|
13752
13797
|
throw new Error("Client-only method called in server mode");
|
|
13753
|
-
const pathLen = Buffer.byteLength(
|
|
13798
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13754
13799
|
let p = 9;
|
|
13755
13800
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
|
|
13756
13801
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13758,7 +13803,7 @@ var require_SFTP = __commonJS({
|
|
|
13758
13803
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13759
13804
|
writeUInt32BE(buf, reqid, 5);
|
|
13760
13805
|
writeUInt32BE(buf, pathLen, p);
|
|
13761
|
-
buf.utf8Write(
|
|
13806
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13762
13807
|
this._requests[reqid] = { cb };
|
|
13763
13808
|
const isBuffered = sendOrBuffer(this, buf);
|
|
13764
13809
|
this._debug && this._debug(
|
|
@@ -13848,10 +13893,10 @@ var require_SFTP = __commonJS({
|
|
|
13848
13893
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} FSTAT`
|
|
13849
13894
|
);
|
|
13850
13895
|
}
|
|
13851
|
-
stat(
|
|
13896
|
+
stat(path6, cb) {
|
|
13852
13897
|
if (this.server)
|
|
13853
13898
|
throw new Error("Client-only method called in server mode");
|
|
13854
|
-
const pathLen = Buffer.byteLength(
|
|
13899
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13855
13900
|
let p = 9;
|
|
13856
13901
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
|
|
13857
13902
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13859,17 +13904,17 @@ var require_SFTP = __commonJS({
|
|
|
13859
13904
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13860
13905
|
writeUInt32BE(buf, reqid, 5);
|
|
13861
13906
|
writeUInt32BE(buf, pathLen, p);
|
|
13862
|
-
buf.utf8Write(
|
|
13907
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13863
13908
|
this._requests[reqid] = { cb };
|
|
13864
13909
|
const isBuffered = sendOrBuffer(this, buf);
|
|
13865
13910
|
this._debug && this._debug(
|
|
13866
13911
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} STAT`
|
|
13867
13912
|
);
|
|
13868
13913
|
}
|
|
13869
|
-
lstat(
|
|
13914
|
+
lstat(path6, cb) {
|
|
13870
13915
|
if (this.server)
|
|
13871
13916
|
throw new Error("Client-only method called in server mode");
|
|
13872
|
-
const pathLen = Buffer.byteLength(
|
|
13917
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13873
13918
|
let p = 9;
|
|
13874
13919
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
|
|
13875
13920
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13877,17 +13922,17 @@ var require_SFTP = __commonJS({
|
|
|
13877
13922
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13878
13923
|
writeUInt32BE(buf, reqid, 5);
|
|
13879
13924
|
writeUInt32BE(buf, pathLen, p);
|
|
13880
|
-
buf.utf8Write(
|
|
13925
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13881
13926
|
this._requests[reqid] = { cb };
|
|
13882
13927
|
const isBuffered = sendOrBuffer(this, buf);
|
|
13883
13928
|
this._debug && this._debug(
|
|
13884
13929
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} LSTAT`
|
|
13885
13930
|
);
|
|
13886
13931
|
}
|
|
13887
|
-
opendir(
|
|
13932
|
+
opendir(path6, cb) {
|
|
13888
13933
|
if (this.server)
|
|
13889
13934
|
throw new Error("Client-only method called in server mode");
|
|
13890
|
-
const pathLen = Buffer.byteLength(
|
|
13935
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13891
13936
|
let p = 9;
|
|
13892
13937
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
|
|
13893
13938
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13895,14 +13940,14 @@ var require_SFTP = __commonJS({
|
|
|
13895
13940
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13896
13941
|
writeUInt32BE(buf, reqid, 5);
|
|
13897
13942
|
writeUInt32BE(buf, pathLen, p);
|
|
13898
|
-
buf.utf8Write(
|
|
13943
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13899
13944
|
this._requests[reqid] = { cb };
|
|
13900
13945
|
const isBuffered = sendOrBuffer(this, buf);
|
|
13901
13946
|
this._debug && this._debug(
|
|
13902
13947
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} OPENDIR`
|
|
13903
13948
|
);
|
|
13904
13949
|
}
|
|
13905
|
-
setstat(
|
|
13950
|
+
setstat(path6, attrs, cb) {
|
|
13906
13951
|
if (this.server)
|
|
13907
13952
|
throw new Error("Client-only method called in server mode");
|
|
13908
13953
|
let flags = 0;
|
|
@@ -13914,7 +13959,7 @@ var require_SFTP = __commonJS({
|
|
|
13914
13959
|
} else if (typeof attrs === "function") {
|
|
13915
13960
|
cb = attrs;
|
|
13916
13961
|
}
|
|
13917
|
-
const pathLen = Buffer.byteLength(
|
|
13962
|
+
const pathLen = Buffer.byteLength(path6);
|
|
13918
13963
|
let p = 9;
|
|
13919
13964
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + attrsLen);
|
|
13920
13965
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -13922,7 +13967,7 @@ var require_SFTP = __commonJS({
|
|
|
13922
13967
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
13923
13968
|
writeUInt32BE(buf, reqid, 5);
|
|
13924
13969
|
writeUInt32BE(buf, pathLen, p);
|
|
13925
|
-
buf.utf8Write(
|
|
13970
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
13926
13971
|
writeUInt32BE(buf, flags, p += pathLen);
|
|
13927
13972
|
if (attrsLen) {
|
|
13928
13973
|
p += 4;
|
|
@@ -13982,8 +14027,8 @@ var require_SFTP = __commonJS({
|
|
|
13982
14027
|
mtime: toUnixTimestamp(mtime)
|
|
13983
14028
|
}, cb);
|
|
13984
14029
|
}
|
|
13985
|
-
utimes(
|
|
13986
|
-
return this.setstat(
|
|
14030
|
+
utimes(path6, atime, mtime, cb) {
|
|
14031
|
+
return this.setstat(path6, {
|
|
13987
14032
|
atime: toUnixTimestamp(atime),
|
|
13988
14033
|
mtime: toUnixTimestamp(mtime)
|
|
13989
14034
|
}, cb);
|
|
@@ -13994,8 +14039,8 @@ var require_SFTP = __commonJS({
|
|
|
13994
14039
|
gid
|
|
13995
14040
|
}, cb);
|
|
13996
14041
|
}
|
|
13997
|
-
chown(
|
|
13998
|
-
return this.setstat(
|
|
14042
|
+
chown(path6, uid, gid, cb) {
|
|
14043
|
+
return this.setstat(path6, {
|
|
13999
14044
|
uid,
|
|
14000
14045
|
gid
|
|
14001
14046
|
}, cb);
|
|
@@ -14005,15 +14050,15 @@ var require_SFTP = __commonJS({
|
|
|
14005
14050
|
mode
|
|
14006
14051
|
}, cb);
|
|
14007
14052
|
}
|
|
14008
|
-
chmod(
|
|
14009
|
-
return this.setstat(
|
|
14053
|
+
chmod(path6, mode, cb) {
|
|
14054
|
+
return this.setstat(path6, {
|
|
14010
14055
|
mode
|
|
14011
14056
|
}, cb);
|
|
14012
14057
|
}
|
|
14013
|
-
readlink(
|
|
14058
|
+
readlink(path6, cb) {
|
|
14014
14059
|
if (this.server)
|
|
14015
14060
|
throw new Error("Client-only method called in server mode");
|
|
14016
|
-
const pathLen = Buffer.byteLength(
|
|
14061
|
+
const pathLen = Buffer.byteLength(path6);
|
|
14017
14062
|
let p = 9;
|
|
14018
14063
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
|
|
14019
14064
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -14021,7 +14066,7 @@ var require_SFTP = __commonJS({
|
|
|
14021
14066
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
14022
14067
|
writeUInt32BE(buf, reqid, 5);
|
|
14023
14068
|
writeUInt32BE(buf, pathLen, p);
|
|
14024
|
-
buf.utf8Write(
|
|
14069
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
14025
14070
|
this._requests[reqid] = {
|
|
14026
14071
|
cb: (err, names) => {
|
|
14027
14072
|
if (typeof cb !== "function")
|
|
@@ -14066,10 +14111,10 @@ var require_SFTP = __commonJS({
|
|
|
14066
14111
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} SYMLINK`
|
|
14067
14112
|
);
|
|
14068
14113
|
}
|
|
14069
|
-
realpath(
|
|
14114
|
+
realpath(path6, cb) {
|
|
14070
14115
|
if (this.server)
|
|
14071
14116
|
throw new Error("Client-only method called in server mode");
|
|
14072
|
-
const pathLen = Buffer.byteLength(
|
|
14117
|
+
const pathLen = Buffer.byteLength(path6);
|
|
14073
14118
|
let p = 9;
|
|
14074
14119
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
|
|
14075
14120
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -14077,7 +14122,7 @@ var require_SFTP = __commonJS({
|
|
|
14077
14122
|
const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
|
|
14078
14123
|
writeUInt32BE(buf, reqid, 5);
|
|
14079
14124
|
writeUInt32BE(buf, pathLen, p);
|
|
14080
|
-
buf.utf8Write(
|
|
14125
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
14081
14126
|
this._requests[reqid] = {
|
|
14082
14127
|
cb: (err, names) => {
|
|
14083
14128
|
if (typeof cb !== "function")
|
|
@@ -14122,13 +14167,13 @@ var require_SFTP = __commonJS({
|
|
|
14122
14167
|
this._debug(`SFTP: Outbound: ${which} posix-rename@openssh.com`);
|
|
14123
14168
|
}
|
|
14124
14169
|
}
|
|
14125
|
-
ext_openssh_statvfs(
|
|
14170
|
+
ext_openssh_statvfs(path6, cb) {
|
|
14126
14171
|
if (this.server)
|
|
14127
14172
|
throw new Error("Client-only method called in server mode");
|
|
14128
14173
|
const ext = this._extensions["statvfs@openssh.com"];
|
|
14129
14174
|
if (!ext || ext !== "2")
|
|
14130
14175
|
throw new Error("Server does not support this extended request");
|
|
14131
|
-
const pathLen = Buffer.byteLength(
|
|
14176
|
+
const pathLen = Buffer.byteLength(path6);
|
|
14132
14177
|
let p = 9;
|
|
14133
14178
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 19 + 4 + pathLen);
|
|
14134
14179
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -14138,7 +14183,7 @@ var require_SFTP = __commonJS({
|
|
|
14138
14183
|
writeUInt32BE(buf, 19, p);
|
|
14139
14184
|
buf.utf8Write("statvfs@openssh.com", p += 4, 19);
|
|
14140
14185
|
writeUInt32BE(buf, pathLen, p += 19);
|
|
14141
|
-
buf.utf8Write(
|
|
14186
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
14142
14187
|
this._requests[reqid] = { extended: "statvfs@openssh.com", cb };
|
|
14143
14188
|
const isBuffered = sendOrBuffer(this, buf);
|
|
14144
14189
|
if (this._debug) {
|
|
@@ -14224,7 +14269,7 @@ var require_SFTP = __commonJS({
|
|
|
14224
14269
|
`SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} fsync@openssh.com`
|
|
14225
14270
|
);
|
|
14226
14271
|
}
|
|
14227
|
-
ext_openssh_lsetstat(
|
|
14272
|
+
ext_openssh_lsetstat(path6, attrs, cb) {
|
|
14228
14273
|
if (this.server)
|
|
14229
14274
|
throw new Error("Client-only method called in server mode");
|
|
14230
14275
|
const ext = this._extensions["lsetstat@openssh.com"];
|
|
@@ -14239,7 +14284,7 @@ var require_SFTP = __commonJS({
|
|
|
14239
14284
|
} else if (typeof attrs === "function") {
|
|
14240
14285
|
cb = attrs;
|
|
14241
14286
|
}
|
|
14242
|
-
const pathLen = Buffer.byteLength(
|
|
14287
|
+
const pathLen = Buffer.byteLength(path6);
|
|
14243
14288
|
let p = 9;
|
|
14244
14289
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 20 + 4 + pathLen + 4 + attrsLen);
|
|
14245
14290
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -14249,7 +14294,7 @@ var require_SFTP = __commonJS({
|
|
|
14249
14294
|
writeUInt32BE(buf, 20, p);
|
|
14250
14295
|
buf.utf8Write("lsetstat@openssh.com", p += 4, 20);
|
|
14251
14296
|
writeUInt32BE(buf, pathLen, p += 20);
|
|
14252
|
-
buf.utf8Write(
|
|
14297
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
14253
14298
|
writeUInt32BE(buf, flags, p += pathLen);
|
|
14254
14299
|
if (attrsLen) {
|
|
14255
14300
|
p += 4;
|
|
@@ -14266,13 +14311,13 @@ var require_SFTP = __commonJS({
|
|
|
14266
14311
|
this._debug(`SFTP: Outbound: ${status} lsetstat@openssh.com`);
|
|
14267
14312
|
}
|
|
14268
14313
|
}
|
|
14269
|
-
ext_openssh_expandPath(
|
|
14314
|
+
ext_openssh_expandPath(path6, cb) {
|
|
14270
14315
|
if (this.server)
|
|
14271
14316
|
throw new Error("Client-only method called in server mode");
|
|
14272
14317
|
const ext = this._extensions["expand-path@openssh.com"];
|
|
14273
14318
|
if (ext !== "1")
|
|
14274
14319
|
throw new Error("Server does not support this extended request");
|
|
14275
|
-
const pathLen = Buffer.byteLength(
|
|
14320
|
+
const pathLen = Buffer.byteLength(path6);
|
|
14276
14321
|
let p = 9;
|
|
14277
14322
|
const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 23 + 4 + pathLen);
|
|
14278
14323
|
writeUInt32BE(buf, buf.length - 4, 0);
|
|
@@ -14282,7 +14327,7 @@ var require_SFTP = __commonJS({
|
|
|
14282
14327
|
writeUInt32BE(buf, 23, p);
|
|
14283
14328
|
buf.utf8Write("expand-path@openssh.com", p += 4, 23);
|
|
14284
14329
|
writeUInt32BE(buf, pathLen, p += 20);
|
|
14285
|
-
buf.utf8Write(
|
|
14330
|
+
buf.utf8Write(path6, p += 4, pathLen);
|
|
14286
14331
|
this._requests[reqid] = {
|
|
14287
14332
|
cb: (err, names) => {
|
|
14288
14333
|
if (typeof cb !== "function")
|
|
@@ -15560,12 +15605,12 @@ var require_SFTP = __commonJS({
|
|
|
15560
15605
|
[REQUEST.LSTAT]: (sftp, payload) => {
|
|
15561
15606
|
bufferParser.init(payload, 1);
|
|
15562
15607
|
const reqID = bufferParser.readUInt32BE();
|
|
15563
|
-
const
|
|
15608
|
+
const path6 = bufferParser.readString(true);
|
|
15564
15609
|
bufferParser.clear();
|
|
15565
|
-
if (
|
|
15610
|
+
if (path6 === void 0)
|
|
15566
15611
|
return doFatalSFTPError(sftp, "Malformed LSTAT packet");
|
|
15567
15612
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received LSTAT (id:${reqID})`);
|
|
15568
|
-
if (!sftp.emit("LSTAT", reqID,
|
|
15613
|
+
if (!sftp.emit("LSTAT", reqID, path6)) {
|
|
15569
15614
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15570
15615
|
}
|
|
15571
15616
|
},
|
|
@@ -15584,13 +15629,13 @@ var require_SFTP = __commonJS({
|
|
|
15584
15629
|
[REQUEST.SETSTAT]: (sftp, payload) => {
|
|
15585
15630
|
bufferParser.init(payload, 1);
|
|
15586
15631
|
const reqID = bufferParser.readUInt32BE();
|
|
15587
|
-
const
|
|
15632
|
+
const path6 = bufferParser.readString(true);
|
|
15588
15633
|
const attrs = readAttrs(sftp._biOpt);
|
|
15589
15634
|
bufferParser.clear();
|
|
15590
15635
|
if (attrs === void 0)
|
|
15591
15636
|
return doFatalSFTPError(sftp, "Malformed SETSTAT packet");
|
|
15592
15637
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received SETSTAT (id:${reqID})`);
|
|
15593
|
-
if (!sftp.emit("SETSTAT", reqID,
|
|
15638
|
+
if (!sftp.emit("SETSTAT", reqID, path6, attrs)) {
|
|
15594
15639
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15595
15640
|
}
|
|
15596
15641
|
},
|
|
@@ -15612,12 +15657,12 @@ var require_SFTP = __commonJS({
|
|
|
15612
15657
|
[REQUEST.OPENDIR]: (sftp, payload) => {
|
|
15613
15658
|
bufferParser.init(payload, 1);
|
|
15614
15659
|
const reqID = bufferParser.readUInt32BE();
|
|
15615
|
-
const
|
|
15660
|
+
const path6 = bufferParser.readString(true);
|
|
15616
15661
|
bufferParser.clear();
|
|
15617
|
-
if (
|
|
15662
|
+
if (path6 === void 0)
|
|
15618
15663
|
return doFatalSFTPError(sftp, "Malformed OPENDIR packet");
|
|
15619
15664
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received OPENDIR (id:${reqID})`);
|
|
15620
|
-
if (!sftp.emit("OPENDIR", reqID,
|
|
15665
|
+
if (!sftp.emit("OPENDIR", reqID, path6)) {
|
|
15621
15666
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15622
15667
|
}
|
|
15623
15668
|
},
|
|
@@ -15636,63 +15681,63 @@ var require_SFTP = __commonJS({
|
|
|
15636
15681
|
[REQUEST.REMOVE]: (sftp, payload) => {
|
|
15637
15682
|
bufferParser.init(payload, 1);
|
|
15638
15683
|
const reqID = bufferParser.readUInt32BE();
|
|
15639
|
-
const
|
|
15684
|
+
const path6 = bufferParser.readString(true);
|
|
15640
15685
|
bufferParser.clear();
|
|
15641
|
-
if (
|
|
15686
|
+
if (path6 === void 0)
|
|
15642
15687
|
return doFatalSFTPError(sftp, "Malformed REMOVE packet");
|
|
15643
15688
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received REMOVE (id:${reqID})`);
|
|
15644
|
-
if (!sftp.emit("REMOVE", reqID,
|
|
15689
|
+
if (!sftp.emit("REMOVE", reqID, path6)) {
|
|
15645
15690
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15646
15691
|
}
|
|
15647
15692
|
},
|
|
15648
15693
|
[REQUEST.MKDIR]: (sftp, payload) => {
|
|
15649
15694
|
bufferParser.init(payload, 1);
|
|
15650
15695
|
const reqID = bufferParser.readUInt32BE();
|
|
15651
|
-
const
|
|
15696
|
+
const path6 = bufferParser.readString(true);
|
|
15652
15697
|
const attrs = readAttrs(sftp._biOpt);
|
|
15653
15698
|
bufferParser.clear();
|
|
15654
15699
|
if (attrs === void 0)
|
|
15655
15700
|
return doFatalSFTPError(sftp, "Malformed MKDIR packet");
|
|
15656
15701
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received MKDIR (id:${reqID})`);
|
|
15657
|
-
if (!sftp.emit("MKDIR", reqID,
|
|
15702
|
+
if (!sftp.emit("MKDIR", reqID, path6, attrs)) {
|
|
15658
15703
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15659
15704
|
}
|
|
15660
15705
|
},
|
|
15661
15706
|
[REQUEST.RMDIR]: (sftp, payload) => {
|
|
15662
15707
|
bufferParser.init(payload, 1);
|
|
15663
15708
|
const reqID = bufferParser.readUInt32BE();
|
|
15664
|
-
const
|
|
15709
|
+
const path6 = bufferParser.readString(true);
|
|
15665
15710
|
bufferParser.clear();
|
|
15666
|
-
if (
|
|
15711
|
+
if (path6 === void 0)
|
|
15667
15712
|
return doFatalSFTPError(sftp, "Malformed RMDIR packet");
|
|
15668
15713
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received RMDIR (id:${reqID})`);
|
|
15669
|
-
if (!sftp.emit("RMDIR", reqID,
|
|
15714
|
+
if (!sftp.emit("RMDIR", reqID, path6)) {
|
|
15670
15715
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15671
15716
|
}
|
|
15672
15717
|
},
|
|
15673
15718
|
[REQUEST.REALPATH]: (sftp, payload) => {
|
|
15674
15719
|
bufferParser.init(payload, 1);
|
|
15675
15720
|
const reqID = bufferParser.readUInt32BE();
|
|
15676
|
-
const
|
|
15721
|
+
const path6 = bufferParser.readString(true);
|
|
15677
15722
|
bufferParser.clear();
|
|
15678
|
-
if (
|
|
15723
|
+
if (path6 === void 0)
|
|
15679
15724
|
return doFatalSFTPError(sftp, "Malformed REALPATH packet");
|
|
15680
15725
|
sftp._debug && sftp._debug(
|
|
15681
15726
|
`SFTP: Inbound: Received REALPATH (id:${reqID})`
|
|
15682
15727
|
);
|
|
15683
|
-
if (!sftp.emit("REALPATH", reqID,
|
|
15728
|
+
if (!sftp.emit("REALPATH", reqID, path6)) {
|
|
15684
15729
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15685
15730
|
}
|
|
15686
15731
|
},
|
|
15687
15732
|
[REQUEST.STAT]: (sftp, payload) => {
|
|
15688
15733
|
bufferParser.init(payload, 1);
|
|
15689
15734
|
const reqID = bufferParser.readUInt32BE();
|
|
15690
|
-
const
|
|
15735
|
+
const path6 = bufferParser.readString(true);
|
|
15691
15736
|
bufferParser.clear();
|
|
15692
|
-
if (
|
|
15737
|
+
if (path6 === void 0)
|
|
15693
15738
|
return doFatalSFTPError(sftp, "Malformed STAT packet");
|
|
15694
15739
|
sftp._debug && sftp._debug(`SFTP: Inbound: Received STAT (id:${reqID})`);
|
|
15695
|
-
if (!sftp.emit("STAT", reqID,
|
|
15740
|
+
if (!sftp.emit("STAT", reqID, path6)) {
|
|
15696
15741
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15697
15742
|
}
|
|
15698
15743
|
},
|
|
@@ -15712,14 +15757,14 @@ var require_SFTP = __commonJS({
|
|
|
15712
15757
|
[REQUEST.READLINK]: (sftp, payload) => {
|
|
15713
15758
|
bufferParser.init(payload, 1);
|
|
15714
15759
|
const reqID = bufferParser.readUInt32BE();
|
|
15715
|
-
const
|
|
15760
|
+
const path6 = bufferParser.readString(true);
|
|
15716
15761
|
bufferParser.clear();
|
|
15717
|
-
if (
|
|
15762
|
+
if (path6 === void 0)
|
|
15718
15763
|
return doFatalSFTPError(sftp, "Malformed READLINK packet");
|
|
15719
15764
|
sftp._debug && sftp._debug(
|
|
15720
15765
|
`SFTP: Inbound: Received READLINK (id:${reqID})`
|
|
15721
15766
|
);
|
|
15722
|
-
if (!sftp.emit("READLINK", reqID,
|
|
15767
|
+
if (!sftp.emit("READLINK", reqID, path6)) {
|
|
15723
15768
|
sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
|
|
15724
15769
|
}
|
|
15725
15770
|
},
|
|
@@ -15790,7 +15835,7 @@ var require_SFTP = __commonJS({
|
|
|
15790
15835
|
function roundUpToMultipleOf8(n) {
|
|
15791
15836
|
return n + 7 & ~7;
|
|
15792
15837
|
}
|
|
15793
|
-
function ReadStream(sftp,
|
|
15838
|
+
function ReadStream(sftp, path6, options) {
|
|
15794
15839
|
if (options === void 0)
|
|
15795
15840
|
options = {};
|
|
15796
15841
|
else if (typeof options === "string")
|
|
@@ -15804,7 +15849,7 @@ var require_SFTP = __commonJS({
|
|
|
15804
15849
|
options.emitClose = false;
|
|
15805
15850
|
options.autoDestroy = false;
|
|
15806
15851
|
ReadableStream.call(this, options);
|
|
15807
|
-
this.path =
|
|
15852
|
+
this.path = path6;
|
|
15808
15853
|
this.flags = options.flags === void 0 ? "r" : options.flags;
|
|
15809
15854
|
this.mode = options.mode === void 0 ? 438 : options.mode;
|
|
15810
15855
|
this.start = options.start;
|
|
@@ -15935,7 +15980,7 @@ var require_SFTP = __commonJS({
|
|
|
15935
15980
|
},
|
|
15936
15981
|
configurable: true
|
|
15937
15982
|
});
|
|
15938
|
-
function WriteStream(sftp,
|
|
15983
|
+
function WriteStream(sftp, path6, options) {
|
|
15939
15984
|
if (options === void 0)
|
|
15940
15985
|
options = {};
|
|
15941
15986
|
else if (typeof options === "string")
|
|
@@ -15947,7 +15992,7 @@ var require_SFTP = __commonJS({
|
|
|
15947
15992
|
options.emitClose = false;
|
|
15948
15993
|
options.autoDestroy = false;
|
|
15949
15994
|
WritableStream.call(this, options);
|
|
15950
|
-
this.path =
|
|
15995
|
+
this.path = path6;
|
|
15951
15996
|
this.flags = options.flags === void 0 ? "w" : options.flags;
|
|
15952
15997
|
this.mode = options.mode === void 0 ? 438 : options.mode;
|
|
15953
15998
|
this.start = options.start;
|
|
@@ -16862,7 +16907,7 @@ var require_client = __commonJS({
|
|
|
16862
16907
|
let sawHeader = false;
|
|
16863
16908
|
if (this._protocol)
|
|
16864
16909
|
this._protocol.cleanup();
|
|
16865
|
-
const DEBUG_HANDLER = !debug ? void 0 : (p,
|
|
16910
|
+
const DEBUG_HANDLER = !debug ? void 0 : (p, display, msg) => {
|
|
16866
16911
|
debug(`Debug output from server: ${JSON.stringify(msg)}`);
|
|
16867
16912
|
};
|
|
16868
16913
|
let serverSigAlgs;
|
|
@@ -18854,7 +18899,7 @@ var require_server = __commonJS({
|
|
|
18854
18899
|
function onClientPreHeaderError(err) {
|
|
18855
18900
|
}
|
|
18856
18901
|
this.on("error", onClientPreHeaderError);
|
|
18857
|
-
const DEBUG_HANDLER = !debug ? void 0 : (p,
|
|
18902
|
+
const DEBUG_HANDLER = !debug ? void 0 : (p, display, msg) => {
|
|
18858
18903
|
debug(`Debug output from client: ${JSON.stringify(msg)}`);
|
|
18859
18904
|
};
|
|
18860
18905
|
const kaIntvl = typeof srvCfg.keepaliveInterval === "number" && isFinite(srvCfg.keepaliveInterval) && srvCfg.keepaliveInterval > 0 ? srvCfg.keepaliveInterval : typeof Server.KEEPALIVE_CLIENT_INTERVAL === "number" && isFinite(Server.KEEPALIVE_CLIENT_INTERVAL) && Server.KEEPALIVE_CLIENT_INTERVAL > 0 ? Server.KEEPALIVE_CLIENT_INTERVAL : -1;
|
|
@@ -19690,7 +19735,7 @@ var require_keygen = __commonJS({
|
|
|
19690
19735
|
generateKeyPair: generateKeyPair_,
|
|
19691
19736
|
generateKeyPairSync: generateKeyPairSync_,
|
|
19692
19737
|
getCurves,
|
|
19693
|
-
randomBytes
|
|
19738
|
+
randomBytes: randomBytes2
|
|
19694
19739
|
} = __require("crypto");
|
|
19695
19740
|
var { Ber } = require_lib();
|
|
19696
19741
|
var bcrypt_pbkdf = require_bcrypt_pbkdf().pbkdf;
|
|
@@ -19954,7 +19999,7 @@ var require_keygen = __commonJS({
|
|
|
19954
19999
|
rounds = opts.rounds;
|
|
19955
20000
|
}
|
|
19956
20001
|
const gen = Buffer.allocUnsafe(cipher.keyLen + cipher.ivLen);
|
|
19957
|
-
const salt =
|
|
20002
|
+
const salt = randomBytes2(SALT_LEN);
|
|
19958
20003
|
const r = bcrypt_pbkdf(
|
|
19959
20004
|
passphrase,
|
|
19960
20005
|
passphrase.length,
|
|
@@ -19993,7 +20038,7 @@ var require_keygen = __commonJS({
|
|
|
19993
20038
|
const kdfOptions = encrypted ? encrypted.kdfOptions : Buffer.alloc(0);
|
|
19994
20039
|
const blockLen = encrypted ? encrypted.cipher.blockLen : 8;
|
|
19995
20040
|
const parsed = parseDERs(keyType, pub, priv);
|
|
19996
|
-
const checkInt =
|
|
20041
|
+
const checkInt = randomBytes2(4);
|
|
19997
20042
|
const commentBin = Buffer.from(comment);
|
|
19998
20043
|
const privBlobLen = 4 + 4 + parsed.priv.length + 4 + commentBin.length;
|
|
19999
20044
|
let padding = [];
|
|
@@ -20153,9 +20198,9 @@ var require_lib2 = __commonJS({
|
|
|
20153
20198
|
|
|
20154
20199
|
// src/lib/agent/launch.ts
|
|
20155
20200
|
import { spawn } from "child_process";
|
|
20156
|
-
import { randomUUID as
|
|
20201
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
20157
20202
|
import { appendFileSync, mkdirSync } from "fs";
|
|
20158
|
-
import
|
|
20203
|
+
import path5 from "path";
|
|
20159
20204
|
|
|
20160
20205
|
// ../../packages/agent-host/dist/env.js
|
|
20161
20206
|
var PASSTHROUGH_ENV_NAMES = [
|
|
@@ -20476,17 +20521,6 @@ function buildPiLaunch(options) {
|
|
|
20476
20521
|
};
|
|
20477
20522
|
}
|
|
20478
20523
|
|
|
20479
|
-
// ../../packages/remote-tools/dist/backend.js
|
|
20480
|
-
var SANDBOX_TOOL_USER = "agent";
|
|
20481
|
-
var SandboxUnavailableError = class extends Error {
|
|
20482
|
-
reason;
|
|
20483
|
-
constructor(reason, options) {
|
|
20484
|
-
super(`Sandbox unavailable, tools are disabled (no local fallback): ${reason}`, options);
|
|
20485
|
-
this.name = "SandboxUnavailableError";
|
|
20486
|
-
this.reason = reason;
|
|
20487
|
-
}
|
|
20488
|
-
};
|
|
20489
|
-
|
|
20490
20524
|
// ../../packages/remote-tools/dist/broker.js
|
|
20491
20525
|
var import_ssh2 = __toESM(require_lib2());
|
|
20492
20526
|
var { utils } = import_ssh2.default;
|
|
@@ -20518,12 +20552,12 @@ var BrokerConnector = class {
|
|
|
20518
20552
|
get sandboxId() {
|
|
20519
20553
|
return this.sandboxIdValue;
|
|
20520
20554
|
}
|
|
20521
|
-
async post(
|
|
20555
|
+
async post(path6, body, signal) {
|
|
20522
20556
|
const doFetch = this.options.fetch ?? fetch;
|
|
20523
20557
|
const timeout = AbortSignal.timeout(this.options.timeoutMs ?? 12e4);
|
|
20524
20558
|
let response;
|
|
20525
20559
|
try {
|
|
20526
|
-
response = await doFetch(`${this.options.apiUrl.replace(/\/+$/, "")}/api/sandboxes/${
|
|
20560
|
+
response = await doFetch(`${this.options.apiUrl.replace(/\/+$/, "")}/api/sandboxes/${path6}`, {
|
|
20527
20561
|
method: "POST",
|
|
20528
20562
|
redirect: "error",
|
|
20529
20563
|
headers: { "content-type": "application/json" },
|
|
@@ -20646,47 +20680,6 @@ function serveSandboxChannel(channel, connector, options = {}) {
|
|
|
20646
20680
|
return { close: () => replies.end() };
|
|
20647
20681
|
}
|
|
20648
20682
|
|
|
20649
|
-
// src/lib/agent/compute.ts
|
|
20650
|
-
function computeCreditObserver(log2) {
|
|
20651
|
-
return async (observation) => {
|
|
20652
|
-
try {
|
|
20653
|
-
const { topUp } = await onComputeBalanceObserved(observation);
|
|
20654
|
-
if (topUp.action === "bought") log2("Compute credit auto-top-up bought one chunk");
|
|
20655
|
-
else if (topUp.action === "skipped")
|
|
20656
|
-
log2(`Compute credit auto-top-up skipped: ${topUp.reason}`);
|
|
20657
|
-
return topUp.action === "bought";
|
|
20658
|
-
} catch (error) {
|
|
20659
|
-
log2(
|
|
20660
|
-
`Compute credit auto-top-up failed: ${error.code ?? error.message}`
|
|
20661
|
-
);
|
|
20662
|
-
return false;
|
|
20663
|
-
}
|
|
20664
|
-
};
|
|
20665
|
-
}
|
|
20666
|
-
function insufficientCredit(error) {
|
|
20667
|
-
return error instanceof SandboxUnavailableError && /\binsufficient_credit\b/.test(error.reason);
|
|
20668
|
-
}
|
|
20669
|
-
async function openSandbox(createBroker, observe) {
|
|
20670
|
-
const first = createBroker();
|
|
20671
|
-
try {
|
|
20672
|
-
await first.connect("start");
|
|
20673
|
-
return first;
|
|
20674
|
-
} catch (error) {
|
|
20675
|
-
if (!insufficientCredit(error)) throw error;
|
|
20676
|
-
if (!await observe({ creditWarning: "credit_exhausted" })) {
|
|
20677
|
-
throw new AgentLaunchError("insufficient_credit", error.reason);
|
|
20678
|
-
}
|
|
20679
|
-
}
|
|
20680
|
-
const retry = createBroker();
|
|
20681
|
-
try {
|
|
20682
|
-
await retry.connect("start");
|
|
20683
|
-
return retry;
|
|
20684
|
-
} catch (error) {
|
|
20685
|
-
if (insufficientCredit(error)) throw new AgentLaunchError("insufficient_credit", error.reason);
|
|
20686
|
-
throw error;
|
|
20687
|
-
}
|
|
20688
|
-
}
|
|
20689
|
-
|
|
20690
20683
|
// src/lib/agent/extensions.ts
|
|
20691
20684
|
import { existsSync as existsSync2 } from "fs";
|
|
20692
20685
|
import path3 from "path";
|
|
@@ -20709,277 +20702,11 @@ function piExtensionPath(entry) {
|
|
|
20709
20702
|
return found;
|
|
20710
20703
|
}
|
|
20711
20704
|
|
|
20712
|
-
// ../../node_modules/.pnpm/@lucid-agents+xgate-client@0.1.6_@solana+sysvars@5.5.1_typescript@5.7.3_zod@3.25.76/node_modules/@lucid-agents/xgate-client/dist/types.js
|
|
20713
|
-
var XgateError = class extends Error {
|
|
20714
|
-
code;
|
|
20715
|
-
constructor(code) {
|
|
20716
|
-
super(`Xgate: ${code}. Inspect /xgate status before another purchase.`);
|
|
20717
|
-
this.name = "XgateError";
|
|
20718
|
-
this.code = code;
|
|
20719
|
-
}
|
|
20720
|
-
};
|
|
20721
|
-
function requireValue(condition, code) {
|
|
20722
|
-
if (!condition)
|
|
20723
|
-
throw new XgateError(code);
|
|
20724
|
-
}
|
|
20725
|
-
function record(value) {
|
|
20726
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
20727
|
-
}
|
|
20728
|
-
function atomic(value) {
|
|
20729
|
-
requireValue(typeof value === "string" && /^(0|[1-9][0-9]{0,12})$/.test(value), "invalid_amount");
|
|
20730
|
-
const n = BigInt(value);
|
|
20731
|
-
requireValue(n <= 1000000000000n, "amount_bound");
|
|
20732
|
-
return n;
|
|
20733
|
-
}
|
|
20734
|
-
function origin(value, loopback = false) {
|
|
20735
|
-
const u = new URL(value);
|
|
20736
|
-
requireValue((u.protocol === "https:" || loopback && u.protocol === "http:" && ["127.0.0.1", "[::1]"].includes(u.hostname)) && !u.username && !u.password && u.pathname === "/" && !u.search && !u.hash, "invalid_origin");
|
|
20737
|
-
return u.origin;
|
|
20738
|
-
}
|
|
20739
|
-
function route(value) {
|
|
20740
|
-
requireValue([
|
|
20741
|
-
"/v1/chat/completions",
|
|
20742
|
-
"/providers/openai/v1/responses",
|
|
20743
|
-
"/providers/anthropic/v1/messages"
|
|
20744
|
-
].includes(String(value)), "invalid_route");
|
|
20745
|
-
}
|
|
20746
|
-
|
|
20747
|
-
// ../../node_modules/.pnpm/@lucid-agents+pi-xgate@0.1.6_@earendil-works+pi-ai@0.85.1_@earendil-works+pi-coding-agent@0.8_344x6vs3jrzh5eh3xewwgv3ik4/node_modules/@lucid-agents/pi-xgate/dist/transport.js
|
|
20748
|
-
var XgatePurchaseError = class extends XgateError {
|
|
20749
|
-
invocationId;
|
|
20750
|
-
pending;
|
|
20751
|
-
payment;
|
|
20752
|
-
constructor(code, invocationId, pending, payment) {
|
|
20753
|
-
super(code);
|
|
20754
|
-
this.name = "XgatePurchaseError";
|
|
20755
|
-
this.message = pending ? `Xgate: ${code}. The payment outcome is unknown; do not retry. Reconcile it before another purchase.` : `Xgate: ${code}. Inspect the payment status before another purchase.`;
|
|
20756
|
-
this.invocationId = invocationId;
|
|
20757
|
-
this.pending = pending;
|
|
20758
|
-
if (payment)
|
|
20759
|
-
this.payment = payment;
|
|
20760
|
-
}
|
|
20761
|
-
};
|
|
20762
|
-
|
|
20763
|
-
// ../../node_modules/.pnpm/@lucid-agents+pi-xgate@0.1.6_@earendil-works+pi-ai@0.85.1_@earendil-works+pi-coding-agent@0.8_344x6vs3jrzh5eh3xewwgv3ik4/node_modules/@lucid-agents/pi-xgate/dist/taskmarket.js
|
|
20764
|
-
var RESOLVED_CHARGES = ["none", "released", "settled", "manually_resolved"];
|
|
20765
|
-
var RESOLVED_STATES = ["completed", "failed"];
|
|
20766
|
-
var CATALOG_BYTES = 2 * 1024 * 1024;
|
|
20767
|
-
var REQUEST_BYTES = 8 * 1024 * 1024;
|
|
20768
|
-
var CATALOG_DEADLINE_MS = 15e3;
|
|
20769
|
-
function createTaskMarketTransport(options) {
|
|
20770
|
-
const { payer } = options, base = origin(options.origin), fetcher = options.fetch ?? fetch;
|
|
20771
|
-
if (payer.apiVersion !== 1)
|
|
20772
|
-
throw new XgateError("unsupported_payer_api");
|
|
20773
|
-
const channel = async (payment) => {
|
|
20774
|
-
if (!options.balances || payment.rail.kind !== "session")
|
|
20775
|
-
return;
|
|
20776
|
-
try {
|
|
20777
|
-
const matches = (await options.balances()).filter((b2) => b2.railId === payment.rail.id && b2.network === payment.network && b2.asset === payment.asset);
|
|
20778
|
-
if (matches.length !== 1)
|
|
20779
|
-
return;
|
|
20780
|
-
const b = matches[0];
|
|
20781
|
-
return {
|
|
20782
|
-
depositingAtomic: b.depositing,
|
|
20783
|
-
lockedAtomic: b.locked,
|
|
20784
|
-
chargedAtomic: b.charged,
|
|
20785
|
-
pendingAtomic: b.pending,
|
|
20786
|
-
refundableAtomic: b.refundable
|
|
20787
|
-
};
|
|
20788
|
-
} catch {
|
|
20789
|
-
return;
|
|
20790
|
-
}
|
|
20791
|
-
};
|
|
20792
|
-
return {
|
|
20793
|
-
async models(signal) {
|
|
20794
|
-
const deadline = AbortSignal.timeout(CATALOG_DEADLINE_MS);
|
|
20795
|
-
let response;
|
|
20796
|
-
try {
|
|
20797
|
-
response = await fetcher(base + "/v1/models", {
|
|
20798
|
-
signal: signal ? AbortSignal.any([signal, deadline]) : deadline,
|
|
20799
|
-
redirect: "error",
|
|
20800
|
-
cache: "no-store",
|
|
20801
|
-
credentials: "omit",
|
|
20802
|
-
referrerPolicy: "no-referrer",
|
|
20803
|
-
headers: { accept: "application/json" }
|
|
20804
|
-
});
|
|
20805
|
-
} catch {
|
|
20806
|
-
throw new XgateError("catalog_unavailable");
|
|
20807
|
-
}
|
|
20808
|
-
if (!response.ok) {
|
|
20809
|
-
await response.body?.cancel().catch(() => {
|
|
20810
|
-
});
|
|
20811
|
-
throw new XgateError("catalog_unavailable");
|
|
20812
|
-
}
|
|
20813
|
-
const v = parse(await bounded(response, CATALOG_BYTES));
|
|
20814
|
-
if (!record(v) || !Array.isArray(v.data) || v.data.length > 128)
|
|
20815
|
-
throw new XgateError("invalid_catalog");
|
|
20816
|
-
return v.data.filter((m) => record(m) && (options.models === void 0 || options.models.includes(m.id))).map((m) => ({ ...m, xgate_origin: base }));
|
|
20817
|
-
},
|
|
20818
|
-
async purchase(invocation, signal, onResponse) {
|
|
20819
|
-
route(invocation.route);
|
|
20820
|
-
const body = new TextEncoder().encode(invocation.body);
|
|
20821
|
-
if (body.byteLength === 0 || body.byteLength > REQUEST_BYTES)
|
|
20822
|
-
throw new XgateError("invalid_invocation");
|
|
20823
|
-
const id = invocation.id;
|
|
20824
|
-
let result;
|
|
20825
|
-
try {
|
|
20826
|
-
result = await payer.request({
|
|
20827
|
-
apiVersion: 1,
|
|
20828
|
-
invocationId: id,
|
|
20829
|
-
url: base + invocation.route,
|
|
20830
|
-
method: "POST",
|
|
20831
|
-
// Application headers only: the payer owns every payment header.
|
|
20832
|
-
headers: {
|
|
20833
|
-
"content-type": "application/json",
|
|
20834
|
-
accept: "application/json"
|
|
20835
|
-
},
|
|
20836
|
-
body,
|
|
20837
|
-
limits: { maxRequestBodyBytes: REQUEST_BYTES },
|
|
20838
|
-
...options.allocationId !== void 0 ? { allocationId: options.allocationId } : {},
|
|
20839
|
-
...options.policyRuleId !== void 0 ? { policyRuleId: options.policyRuleId } : {},
|
|
20840
|
-
...options.nonInteractive !== void 0 ? { nonInteractive: options.nonInteractive } : {}
|
|
20841
|
-
}, {
|
|
20842
|
-
...signal ? { signal } : {},
|
|
20843
|
-
...options.confirmPayment ? { confirmPayment: options.confirmPayment } : {}
|
|
20844
|
-
});
|
|
20845
|
-
} catch (error) {
|
|
20846
|
-
throw failure(error, id);
|
|
20847
|
-
}
|
|
20848
|
-
const payment = result.payment;
|
|
20849
|
-
if (result.invocationId !== id || result.apiVersion !== 1)
|
|
20850
|
-
throw new XgatePurchaseError("payer_result_mismatch", id, true, payment && display(payment));
|
|
20851
|
-
if (!payment)
|
|
20852
|
-
throw new XgatePurchaseError(result.response.status === 200 ? "payment_missing" : "request_rejected", id, false);
|
|
20853
|
-
const shown = display(payment);
|
|
20854
|
-
if (payment.charge !== "settled" || typeof payment.settledAmount !== "string")
|
|
20855
|
-
throw new XgatePurchaseError("payment_unverified", id, true, shown);
|
|
20856
|
-
shown.chargedAtomic = payment.settledAmount;
|
|
20857
|
-
try {
|
|
20858
|
-
if (atomic(payment.settledAmount) > atomic(payment.authorizedAmount))
|
|
20859
|
-
throw new XgateError("charge_over_authorization");
|
|
20860
|
-
} catch {
|
|
20861
|
-
throw new XgatePurchaseError("invalid_settlement", id, true, shown);
|
|
20862
|
-
}
|
|
20863
|
-
const r = result.response, h = r.headers;
|
|
20864
|
-
if (r.status !== 200 || !/^application\/json\b/i.test(r.contentType) || h["x-inference-privacy"] !== "anonymous" || h["x-result-retention"] !== "none" || !h["cache-control"]?.includes("no-store"))
|
|
20865
|
-
throw new XgatePurchaseError("response_rejected", id, false, shown);
|
|
20866
|
-
let value;
|
|
20867
|
-
try {
|
|
20868
|
-
value = parse(r.body);
|
|
20869
|
-
} catch {
|
|
20870
|
-
throw new XgatePurchaseError("invalid_response", id, false, shown);
|
|
20871
|
-
}
|
|
20872
|
-
if (!record(value) || typeof value.id !== "string" || value.result_replay_available !== void 0)
|
|
20873
|
-
throw new XgatePurchaseError("invalid_response", id, false, shown);
|
|
20874
|
-
const head = {
|
|
20875
|
-
status: r.status,
|
|
20876
|
-
headers: { "content-type": r.contentType, "cache-control": "no-store" }
|
|
20877
|
-
};
|
|
20878
|
-
try {
|
|
20879
|
-
await onResponse?.(head);
|
|
20880
|
-
} catch {
|
|
20881
|
-
throw new XgatePurchaseError("response_hook_failed", id, false, shown);
|
|
20882
|
-
}
|
|
20883
|
-
const balance = await channel(payment);
|
|
20884
|
-
if (balance)
|
|
20885
|
-
shown.channel = balance;
|
|
20886
|
-
return {
|
|
20887
|
-
body: value,
|
|
20888
|
-
settlement: {
|
|
20889
|
-
chargedAtomic: payment.settledAmount,
|
|
20890
|
-
reference: payment.transaction ?? payment.commitment ?? payment.paymentId
|
|
20891
|
-
},
|
|
20892
|
-
purchase: payment.commitment ?? payment.paymentId,
|
|
20893
|
-
payment: shown
|
|
20894
|
-
};
|
|
20895
|
-
},
|
|
20896
|
-
async status() {
|
|
20897
|
-
return {
|
|
20898
|
-
transport: "taskmarket",
|
|
20899
|
-
origin: base,
|
|
20900
|
-
...options.balances ? {
|
|
20901
|
-
balances: (await options.balances()).map((b) => ({
|
|
20902
|
-
rail: b.railId,
|
|
20903
|
-
network: b.network,
|
|
20904
|
-
asset: b.asset,
|
|
20905
|
-
depositingAtomic: b.depositing,
|
|
20906
|
-
lockedAtomic: b.locked,
|
|
20907
|
-
chargedAtomic: b.charged,
|
|
20908
|
-
pendingAtomic: b.pending,
|
|
20909
|
-
refundableAtomic: b.refundable
|
|
20910
|
-
}))
|
|
20911
|
-
} : {}
|
|
20912
|
-
};
|
|
20913
|
-
},
|
|
20914
|
-
async reconcile(invocationId) {
|
|
20915
|
-
const s = await payer.reconcile(invocationId);
|
|
20916
|
-
return {
|
|
20917
|
-
invocationId: s.invocationId,
|
|
20918
|
-
state: s.state,
|
|
20919
|
-
charge: s.charge,
|
|
20920
|
-
uncertain: s.uncertain,
|
|
20921
|
-
...s.errorCode ? { errorCode: s.errorCode } : {},
|
|
20922
|
-
...s.payment ? { payment: display(s.payment) } : {}
|
|
20923
|
-
};
|
|
20924
|
-
}
|
|
20925
|
-
};
|
|
20926
|
-
}
|
|
20927
|
-
function display(p) {
|
|
20928
|
-
return {
|
|
20929
|
-
network: p.network,
|
|
20930
|
-
scheme: p.scheme,
|
|
20931
|
-
asset: p.asset,
|
|
20932
|
-
payTo: p.payTo,
|
|
20933
|
-
rail: p.rail.kind,
|
|
20934
|
-
authorizedAtomic: p.authorizedAmount,
|
|
20935
|
-
...p.charge === "settled" && p.settledAmount !== void 0 ? { chargedAtomic: p.settledAmount } : {},
|
|
20936
|
-
status: p.charge,
|
|
20937
|
-
...p.transaction ?? p.commitment ? { reference: p.transaction ?? p.commitment } : {}
|
|
20938
|
-
};
|
|
20939
|
-
}
|
|
20940
|
-
function failure(error, id) {
|
|
20941
|
-
const e = error;
|
|
20942
|
-
const code = typeof e?.code === "string" && /^[a-z0-9_]{1,64}$/.test(e.code) ? e.code : "payer_failed";
|
|
20943
|
-
const recorded = e?.invocation;
|
|
20944
|
-
const pending = e?.pending !== false || recorded !== void 0 && !(recorded.uncertain === false && RESOLVED_CHARGES.includes(recorded.charge) && RESOLVED_STATES.includes(recorded.state));
|
|
20945
|
-
const summary = e?.invocation?.payment;
|
|
20946
|
-
return new XgatePurchaseError(code, id, pending, record(summary) ? display(summary) : void 0);
|
|
20947
|
-
}
|
|
20948
|
-
async function bounded(response, limit) {
|
|
20949
|
-
if (!response.body)
|
|
20950
|
-
throw new XgateError("invalid_catalog");
|
|
20951
|
-
const reader = response.body.getReader(), chunks = [];
|
|
20952
|
-
let length = 0;
|
|
20953
|
-
try {
|
|
20954
|
-
for (; ; ) {
|
|
20955
|
-
const part = await reader.read();
|
|
20956
|
-
if (part.done)
|
|
20957
|
-
break;
|
|
20958
|
-
length += part.value.byteLength;
|
|
20959
|
-
if (length > limit)
|
|
20960
|
-
throw new XgateError("catalog_bound");
|
|
20961
|
-
chunks.push(part.value);
|
|
20962
|
-
}
|
|
20963
|
-
} catch (error) {
|
|
20964
|
-
await reader.cancel().catch(() => {
|
|
20965
|
-
});
|
|
20966
|
-
throw error instanceof XgateError ? error : new XgateError("catalog_unavailable");
|
|
20967
|
-
} finally {
|
|
20968
|
-
reader.releaseLock();
|
|
20969
|
-
}
|
|
20970
|
-
return Buffer.concat(chunks, length);
|
|
20971
|
-
}
|
|
20972
|
-
function parse(bytes) {
|
|
20973
|
-
try {
|
|
20974
|
-
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
20975
|
-
} catch {
|
|
20976
|
-
throw new XgateError("invalid_response");
|
|
20977
|
-
}
|
|
20978
|
-
}
|
|
20979
|
-
|
|
20980
20705
|
// src/lib/agent/inference-channel.ts
|
|
20981
20706
|
var MAX_MESSAGE_BYTES2 = 48 * 1024 * 1024;
|
|
20982
20707
|
var CATALOG_TIMEOUT_MS = 3e4;
|
|
20708
|
+
var BUY_TIMEOUT_MS = 5 * 6e4;
|
|
20709
|
+
var CODE = /^[a-z0-9_]{1,64}$/;
|
|
20983
20710
|
function lines2(stream, onLine, onOverflow, maxBytes) {
|
|
20984
20711
|
let chunks = [];
|
|
20985
20712
|
let size = 0;
|
|
@@ -21113,6 +20840,31 @@ function serveInferenceChannel(channel, transport, options = {}) {
|
|
|
21113
20840
|
(typeof request.invocationId === "string" && transport.reconcile ? transport.reconcile(request.invocationId) : Promise.reject(new XgateError("purchase_id_required"))).then((value) => ({ value }))
|
|
21114
20841
|
);
|
|
21115
20842
|
return;
|
|
20843
|
+
case "budget":
|
|
20844
|
+
void answer(
|
|
20845
|
+
request.id,
|
|
20846
|
+
(options.views?.budget ? options.views.budget({ unresolved: [...unresolved] }) : Promise.reject(new XgateError("unsupported_by_transport"))).then((value) => ({ value }))
|
|
20847
|
+
);
|
|
20848
|
+
return;
|
|
20849
|
+
case "credit_offer":
|
|
20850
|
+
void answer(
|
|
20851
|
+
request.id,
|
|
20852
|
+
(options.views?.creditOffer ? options.views.creditOffer() : Promise.reject(new XgateError("unsupported_by_transport"))).then((value) => ({ value }))
|
|
20853
|
+
);
|
|
20854
|
+
return;
|
|
20855
|
+
case "buy_credits": {
|
|
20856
|
+
const amount = request.amountUsd;
|
|
20857
|
+
void answer(
|
|
20858
|
+
request.id,
|
|
20859
|
+
(amount !== void 0 && !(Number.isSafeInteger(amount) && amount > 0) ? Promise.reject(new XgateError("invalid_amount")) : options.views?.buyCredits ? options.views.buyCredits(amount).catch((error) => {
|
|
20860
|
+
const code = error.code;
|
|
20861
|
+
throw new XgateError(
|
|
20862
|
+
typeof code === "string" && CODE.test(code) ? code : "purchase_failed"
|
|
20863
|
+
);
|
|
20864
|
+
}) : Promise.reject(new XgateError("unsupported_by_transport"))).then((value) => ({ value }))
|
|
20865
|
+
);
|
|
20866
|
+
return;
|
|
20867
|
+
}
|
|
21116
20868
|
case "abort":
|
|
21117
20869
|
running.get(request.target)?.abort.abort();
|
|
21118
20870
|
return;
|
|
@@ -21158,170 +20910,6 @@ function serveInferenceChannel(channel, transport, options = {}) {
|
|
|
21158
20910
|
};
|
|
21159
20911
|
}
|
|
21160
20912
|
|
|
21161
|
-
// src/lib/agent/payer.ts
|
|
21162
|
-
function routeOfCatalogRow(row) {
|
|
21163
|
-
return row?.owned_by === "anthropic" ? "/providers/anthropic/v1/messages" : "/providers/openai/v1/responses";
|
|
21164
|
-
}
|
|
21165
|
-
async function createAgentRails(options) {
|
|
21166
|
-
const journalPath = getX402JournalPath();
|
|
21167
|
-
const policyPath = getX402PolicyPath();
|
|
21168
|
-
const loadPolicy = (loadOptions) => loadX402Policy(policyPath, loadOptions);
|
|
21169
|
-
const x402Policy = await loadX402Policy(policyPath);
|
|
21170
|
-
const allocations = createX402Allocations({ journalPath, loadPolicy });
|
|
21171
|
-
return options.policy.rails.map((rail) => {
|
|
21172
|
-
if (rail.wallet.toLowerCase() !== options.walletAddress.toLowerCase()) {
|
|
21173
|
-
throw new AgentLaunchError(
|
|
21174
|
-
"invalid_agent_policy",
|
|
21175
|
-
`Rail ${rail.id} pays from ${rail.wallet}, but the wallet is ${options.walletAddress}`
|
|
21176
|
-
);
|
|
21177
|
-
}
|
|
21178
|
-
let rpcUrl;
|
|
21179
|
-
try {
|
|
21180
|
-
rpcUrl = rpcUrlForNetwork(x402Policy, rail.network);
|
|
21181
|
-
} catch (error) {
|
|
21182
|
-
throw new AgentLaunchError("invalid_agent_policy", error.message);
|
|
21183
|
-
}
|
|
21184
|
-
const channel = {
|
|
21185
|
-
network: rail.network,
|
|
21186
|
-
payer: rail.wallet,
|
|
21187
|
-
receiver: rail.receiver,
|
|
21188
|
-
receiverAuthorizer: rail.receiverAuthorizer,
|
|
21189
|
-
salt: rail.salt
|
|
21190
|
-
};
|
|
21191
|
-
const payer = createBaseChannelPayer({
|
|
21192
|
-
channel,
|
|
21193
|
-
reader: createBaseChannelRpcReader({ channel, rpcUrl, fromBlock: BigInt(rail.fromBlock) }),
|
|
21194
|
-
resourceUrl: `${rail.origin}${rail.route}`,
|
|
21195
|
-
journalPath,
|
|
21196
|
-
loadPolicy,
|
|
21197
|
-
getAccount: options.getAccount,
|
|
21198
|
-
allocationId: rail.allocationId,
|
|
21199
|
-
budgetAmount: rail.budgetAmount,
|
|
21200
|
-
...rail.depositAmount !== void 0 ? { depositAmount: rail.depositAmount } : {},
|
|
21201
|
-
...rail.policyRuleId !== void 0 ? { policyRuleId: rail.policyRuleId } : {},
|
|
21202
|
-
...options.fetch ? { fetch: options.fetch } : {}
|
|
21203
|
-
});
|
|
21204
|
-
const transport = createTaskMarketTransport({
|
|
21205
|
-
payer,
|
|
21206
|
-
origin: rail.origin,
|
|
21207
|
-
allocationId: rail.allocationId,
|
|
21208
|
-
...rail.policyRuleId !== void 0 ? { policyRuleId: rail.policyRuleId } : {},
|
|
21209
|
-
nonInteractive: true,
|
|
21210
|
-
models: options.models,
|
|
21211
|
-
balances: () => allocations.balances(),
|
|
21212
|
-
...options.fetch ? { fetch: options.fetch } : {}
|
|
21213
|
-
});
|
|
21214
|
-
return { rail, payer, transport };
|
|
21215
|
-
});
|
|
21216
|
-
}
|
|
21217
|
-
function bodyModel(body) {
|
|
21218
|
-
try {
|
|
21219
|
-
const model = JSON.parse(body)?.model;
|
|
21220
|
-
return typeof model === "string" ? model : void 0;
|
|
21221
|
-
} catch {
|
|
21222
|
-
return void 0;
|
|
21223
|
-
}
|
|
21224
|
-
}
|
|
21225
|
-
async function neverRecorded(payer, invocationId) {
|
|
21226
|
-
try {
|
|
21227
|
-
await payer.status(invocationId);
|
|
21228
|
-
return false;
|
|
21229
|
-
} catch (error) {
|
|
21230
|
-
return error.code === "invocation_not_found";
|
|
21231
|
-
}
|
|
21232
|
-
}
|
|
21233
|
-
function createAgentTransport(rails) {
|
|
21234
|
-
const byRoute = new Map(rails.map((r) => [r.rail.route, r]));
|
|
21235
|
-
let offered = /* @__PURE__ */ new Map();
|
|
21236
|
-
return {
|
|
21237
|
-
async models(signal) {
|
|
21238
|
-
const seen = /* @__PURE__ */ new Map();
|
|
21239
|
-
const rows = [];
|
|
21240
|
-
for (const { rail, transport } of rails) {
|
|
21241
|
-
for (const row of await transport.models(signal)) {
|
|
21242
|
-
const id = row.id;
|
|
21243
|
-
if (routeOfCatalogRow(row) !== rail.route || typeof id !== "string" || seen.has(id)) {
|
|
21244
|
-
continue;
|
|
21245
|
-
}
|
|
21246
|
-
seen.set(id, rail.route);
|
|
21247
|
-
rows.push(row);
|
|
21248
|
-
}
|
|
21249
|
-
}
|
|
21250
|
-
offered = seen;
|
|
21251
|
-
return rows;
|
|
21252
|
-
},
|
|
21253
|
-
async purchase(invocation, signal, onResponse) {
|
|
21254
|
-
const rail = byRoute.get(invocation.route);
|
|
21255
|
-
if (!rail) {
|
|
21256
|
-
throw new XgatePurchaseError("no_rail_for_route", invocation.id, false);
|
|
21257
|
-
}
|
|
21258
|
-
const model = typeof invocation.body === "string" ? bodyModel(invocation.body) : void 0;
|
|
21259
|
-
if (model === void 0 || offered.get(model) !== invocation.route) {
|
|
21260
|
-
throw new XgatePurchaseError("model_not_offered", invocation.id, false);
|
|
21261
|
-
}
|
|
21262
|
-
const leftover = (await rail.payer.channelStatus()).pendingOperation;
|
|
21263
|
-
if (leftover && leftover.id !== invocation.id) {
|
|
21264
|
-
throw new XgatePurchaseError("channel_operation_pending", invocation.id, false);
|
|
21265
|
-
}
|
|
21266
|
-
try {
|
|
21267
|
-
return await rail.transport.purchase(invocation, signal, onResponse);
|
|
21268
|
-
} catch (error) {
|
|
21269
|
-
if (error instanceof XgatePurchaseError && error.pending && await neverRecorded(rail.payer, invocation.id)) {
|
|
21270
|
-
throw new XgatePurchaseError(
|
|
21271
|
-
error.code === "outcome_uncertain" ? "channel_operation_pending" : error.code,
|
|
21272
|
-
invocation.id,
|
|
21273
|
-
false
|
|
21274
|
-
);
|
|
21275
|
-
}
|
|
21276
|
-
throw error;
|
|
21277
|
-
}
|
|
21278
|
-
},
|
|
21279
|
-
async status() {
|
|
21280
|
-
return {
|
|
21281
|
-
transport: "taskmarket",
|
|
21282
|
-
rails: await Promise.all(
|
|
21283
|
-
rails.map(async ({ rail, transport }) => ({
|
|
21284
|
-
rail: rail.id,
|
|
21285
|
-
...await transport.status()
|
|
21286
|
-
}))
|
|
21287
|
-
)
|
|
21288
|
-
};
|
|
21289
|
-
},
|
|
21290
|
-
async reconcile(invocationId) {
|
|
21291
|
-
for (const { transport } of rails) {
|
|
21292
|
-
try {
|
|
21293
|
-
return await transport.reconcile(invocationId);
|
|
21294
|
-
} catch (error) {
|
|
21295
|
-
if (error.code !== "invocation_not_found") throw error;
|
|
21296
|
-
}
|
|
21297
|
-
}
|
|
21298
|
-
throw new XgateError("invocation_not_found");
|
|
21299
|
-
}
|
|
21300
|
-
};
|
|
21301
|
-
}
|
|
21302
|
-
async function reconcileLeftoverOperations(rails, log2 = () => void 0) {
|
|
21303
|
-
for (const { rail, payer } of rails) {
|
|
21304
|
-
let pending = (await payer.channelStatus()).pendingOperation;
|
|
21305
|
-
if (!pending) continue;
|
|
21306
|
-
if (pending.kind === "payment") {
|
|
21307
|
-
log2(`Reconciling payment ${pending.id} left on rail ${rail.id}`);
|
|
21308
|
-
try {
|
|
21309
|
-
await payer.reconcile(pending.id);
|
|
21310
|
-
} catch (error) {
|
|
21311
|
-
log2(
|
|
21312
|
-
`Payment ${pending.id} could not be reconciled: ${error.code ?? error.message}`
|
|
21313
|
-
);
|
|
21314
|
-
}
|
|
21315
|
-
pending = (await payer.channelStatus()).pendingOperation;
|
|
21316
|
-
if (!pending) continue;
|
|
21317
|
-
}
|
|
21318
|
-
throw new AgentLaunchError(
|
|
21319
|
-
"channel_operation_pending",
|
|
21320
|
-
`The ${rail.id} channel has an unresolved ${pending.kind} operation ${pending.id} from an earlier session; it must be reconciled before anything else is bought on that channel. Try again later.`
|
|
21321
|
-
);
|
|
21322
|
-
}
|
|
21323
|
-
}
|
|
21324
|
-
|
|
21325
20913
|
// src/lib/agent/pi-settings.ts
|
|
21326
20914
|
import { randomUUID } from "crypto";
|
|
21327
20915
|
import { promises as fs } from "fs";
|
|
@@ -21384,110 +20972,1232 @@ async function writeManagedPiSettings(agentDir, managed) {
|
|
|
21384
20972
|
return settings;
|
|
21385
20973
|
}
|
|
21386
20974
|
|
|
21387
|
-
// src/lib/agent/
|
|
20975
|
+
// src/lib/agent/session-budget.ts
|
|
20976
|
+
var COMPUTE_TTL_MS = 6e4;
|
|
20977
|
+
function aggregateBudget(rails, allocations) {
|
|
20978
|
+
const id = rails[0]?.rail.budgetAllocationId;
|
|
20979
|
+
const found = allocations.find((allocation) => allocation.allocationId === id);
|
|
20980
|
+
return found ? { allocationId: found.allocationId, cap: found.caps.amount, used: found.used.total } : null;
|
|
20981
|
+
}
|
|
20982
|
+
function createSessionBudget(options) {
|
|
20983
|
+
const now = options.now ?? Date.now;
|
|
20984
|
+
const readCompute = options.readCompute ?? readComputeView;
|
|
20985
|
+
const buyCompute = options.buyCompute ?? buyComputeChunk;
|
|
20986
|
+
let turns = 0;
|
|
20987
|
+
let charged = 0n;
|
|
20988
|
+
let lastTurn = null;
|
|
20989
|
+
let warning = null;
|
|
20990
|
+
let compute;
|
|
20991
|
+
const running = /* @__PURE__ */ new Set();
|
|
20992
|
+
const track = (work) => {
|
|
20993
|
+
running.add(work);
|
|
20994
|
+
void work.then(
|
|
20995
|
+
() => running.delete(work),
|
|
20996
|
+
() => running.delete(work)
|
|
20997
|
+
);
|
|
20998
|
+
return work;
|
|
20999
|
+
};
|
|
21000
|
+
const inner = options.transport;
|
|
21001
|
+
const transport = {
|
|
21002
|
+
...inner,
|
|
21003
|
+
async purchase(invocation, signal, onResponse) {
|
|
21004
|
+
const result = await inner.purchase(invocation, signal, onResponse);
|
|
21005
|
+
const amount = result.settlement?.chargedAtomic;
|
|
21006
|
+
if (typeof amount === "string" && /^\d{1,40}$/.test(amount)) {
|
|
21007
|
+
turns += 1;
|
|
21008
|
+
charged += BigInt(amount);
|
|
21009
|
+
lastTurn = { invocationId: invocation.id, chargedAtomic: amount };
|
|
21010
|
+
}
|
|
21011
|
+
return result;
|
|
21012
|
+
}
|
|
21013
|
+
};
|
|
21014
|
+
const computeView = () => {
|
|
21015
|
+
if (!compute || now() - compute.at >= COMPUTE_TTL_MS) {
|
|
21016
|
+
compute = {
|
|
21017
|
+
at: now(),
|
|
21018
|
+
value: track(
|
|
21019
|
+
readCompute({
|
|
21020
|
+
warning,
|
|
21021
|
+
...options.observeCompute ? { observe: options.observeCompute } : {}
|
|
21022
|
+
})
|
|
21023
|
+
)
|
|
21024
|
+
};
|
|
21025
|
+
}
|
|
21026
|
+
return compute.value;
|
|
21027
|
+
};
|
|
21028
|
+
return {
|
|
21029
|
+
transport,
|
|
21030
|
+
async view({ unresolved }) {
|
|
21031
|
+
const [channels, allocations, computeValue] = await Promise.all([
|
|
21032
|
+
Promise.all(options.rails.map((rail) => channelView(rail))),
|
|
21033
|
+
computeAllocationId().then((id) => allocationViews(options.rails, [id])),
|
|
21034
|
+
computeView()
|
|
21035
|
+
]);
|
|
21036
|
+
return {
|
|
21037
|
+
version: AGENT_VIEW_VERSION,
|
|
21038
|
+
lastTurn,
|
|
21039
|
+
session: { turns, chargedAtomic: charged.toString() },
|
|
21040
|
+
channels,
|
|
21041
|
+
allocations,
|
|
21042
|
+
unresolved,
|
|
21043
|
+
compute: computeValue,
|
|
21044
|
+
budget: aggregateBudget(options.rails, allocations)
|
|
21045
|
+
};
|
|
21046
|
+
},
|
|
21047
|
+
creditOffer: () => (options.offerCompute ?? computeCreditOffer)(),
|
|
21048
|
+
async buyCredits(amountUsd) {
|
|
21049
|
+
try {
|
|
21050
|
+
return await track(buyCompute(amountUsd));
|
|
21051
|
+
} finally {
|
|
21052
|
+
compute = void 0;
|
|
21053
|
+
}
|
|
21054
|
+
},
|
|
21055
|
+
async settled() {
|
|
21056
|
+
await Promise.allSettled([...running]);
|
|
21057
|
+
},
|
|
21058
|
+
noteCreditWarning(next) {
|
|
21059
|
+
if (next !== warning) compute = void 0;
|
|
21060
|
+
warning = next;
|
|
21061
|
+
}
|
|
21062
|
+
};
|
|
21063
|
+
}
|
|
21064
|
+
|
|
21065
|
+
// src/lib/agent/deposit-window.ts
|
|
21066
|
+
var DEPOSIT_WINDOW_SECONDS = 86400;
|
|
21067
|
+
function depositWindows(total, routes) {
|
|
21068
|
+
const count = BigInt(routes.length);
|
|
21069
|
+
const share = BigInt(total) / count;
|
|
21070
|
+
const remainder = BigInt(total) - share * count;
|
|
21071
|
+
return new Map(
|
|
21072
|
+
routes.map((route, index) => [route, String(index === 0 ? share + remainder : share)])
|
|
21073
|
+
);
|
|
21074
|
+
}
|
|
21075
|
+
var CENT = 10000n;
|
|
21076
|
+
var roundUp = (value, unit) => (value + unit - 1n) / unit * unit;
|
|
21077
|
+
function roundUpToSecond(date) {
|
|
21078
|
+
return new Date(Math.ceil(date.getTime() / 1e3) * 1e3).toISOString().replace(".000Z", "Z");
|
|
21079
|
+
}
|
|
21080
|
+
async function checkDepositWindows(input) {
|
|
21081
|
+
const records = await listX402Payments({}, input.journalPath);
|
|
21082
|
+
const deposit = BigInt(input.limits.deposit) < BigInt(input.limits.total) ? BigInt(input.limits.deposit) : BigInt(input.limits.total);
|
|
21083
|
+
const windows = depositWindows(input.limits.total, input.routes);
|
|
21084
|
+
const availability = (rail, maximum) => x402SpendWindowAvailability({
|
|
21085
|
+
records,
|
|
21086
|
+
ruleId: rail.ruleId,
|
|
21087
|
+
network: rail.network,
|
|
21088
|
+
asset: rail.asset,
|
|
21089
|
+
windowSeconds: DEPOSIT_WINDOW_SECONDS,
|
|
21090
|
+
maximum,
|
|
21091
|
+
requested: deposit,
|
|
21092
|
+
now: input.now
|
|
21093
|
+
});
|
|
21094
|
+
const blocks = [];
|
|
21095
|
+
for (const rail of input.rails) {
|
|
21096
|
+
if (!rail.newChannel) continue;
|
|
21097
|
+
const window2 = windows.get(rail.route);
|
|
21098
|
+
if (window2 === void 0) continue;
|
|
21099
|
+
const result = availability(rail, window2);
|
|
21100
|
+
if (result.fits) continue;
|
|
21101
|
+
blocks.push({
|
|
21102
|
+
railId: rail.railId,
|
|
21103
|
+
route: rail.route,
|
|
21104
|
+
window: window2,
|
|
21105
|
+
used: String(result.used),
|
|
21106
|
+
deposit: String(deposit),
|
|
21107
|
+
...result.fitsAt ? { resetsAt: roundUpToSecond(result.fitsAt) } : {}
|
|
21108
|
+
});
|
|
21109
|
+
}
|
|
21110
|
+
if (blocks.length === 0) return void 0;
|
|
21111
|
+
const needs = /* @__PURE__ */ new Map();
|
|
21112
|
+
for (const rail of input.rails) {
|
|
21113
|
+
if (!input.routes.includes(rail.route)) continue;
|
|
21114
|
+
const used = availability(rail, "0").used;
|
|
21115
|
+
needs.set(rail.route, (needs.get(rail.route) ?? 0n) + used + deposit);
|
|
21116
|
+
}
|
|
21117
|
+
const fitsAll = (total2) => {
|
|
21118
|
+
const shares = depositWindows(String(total2), input.routes);
|
|
21119
|
+
return [...needs].every(([route, need]) => BigInt(shares.get(route)) >= need);
|
|
21120
|
+
};
|
|
21121
|
+
const n = BigInt(input.routes.length);
|
|
21122
|
+
const first = needs.get(input.routes[0]) ?? 0n;
|
|
21123
|
+
const others = input.routes.slice(1).reduce((max, route) => (needs.get(route) ?? 0n) > max ? needs.get(route) : max, 0n);
|
|
21124
|
+
const q = others > first - (n - 1n) ? others : first - (n - 1n);
|
|
21125
|
+
let total = n * q + (first > q ? first - q : 0n);
|
|
21126
|
+
if (input.floor !== void 0 && input.floor > total) total = input.floor;
|
|
21127
|
+
total = roundUp(total, CENT);
|
|
21128
|
+
if (!fitsAll(total)) {
|
|
21129
|
+
const largest = first > others ? first : others;
|
|
21130
|
+
const even = (total + n - 1n) / n;
|
|
21131
|
+
total = n * roundUp(even > largest ? even : largest, CENT);
|
|
21132
|
+
}
|
|
21133
|
+
const resets = blocks.map((block) => block.resetsAt);
|
|
21134
|
+
const resetsAt = resets.every((value) => value !== void 0) ? resets.reduce((latest, value) => value > latest ? value : latest) : void 0;
|
|
21135
|
+
return { blocks, minimumTotal: String(total), ...resetsAt ? { resetsAt } : {} };
|
|
21136
|
+
}
|
|
21137
|
+
|
|
21138
|
+
// src/lib/agent/onboarding.ts
|
|
21139
|
+
import { randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
21140
|
+
import { createPublicClient, erc20Abi, http } from "viem";
|
|
21141
|
+
|
|
21142
|
+
// src/lib/agent/rail-profile.ts
|
|
21388
21143
|
import { promises as fs2 } from "fs";
|
|
21389
|
-
import path5 from "path";
|
|
21390
21144
|
import { z } from "zod";
|
|
21391
|
-
var
|
|
21392
|
-
|
|
21393
|
-
|
|
21394
|
-
|
|
21145
|
+
var AGENT_RAIL_PROFILE_ENV = "TASKMARKET_AGENT_RAIL_PROFILE";
|
|
21146
|
+
var AGENT_RAIL_PROFILE_FILE_ENV = "TASKMARKET_AGENT_RAIL_PROFILE_FILE";
|
|
21147
|
+
var AGENT_DEVELOPER_ENV = "TASKMARKET_AGENT_DEVELOPER";
|
|
21148
|
+
var BASE_MAINNET = "eip155:8453";
|
|
21395
21149
|
var address = z.string().regex(/^0x[0-9a-fA-F]{40}$/, "expected a 0x-prefixed 20-byte address");
|
|
21396
|
-
var
|
|
21397
|
-
|
|
21398
|
-
|
|
21399
|
-
const url = new URL(value);
|
|
21400
|
-
return url.protocol === "https:" && !url.username && !url.password && url.pathname === "/" && !url.search && !url.hash && !value.endsWith("/");
|
|
21401
|
-
}, "expected an HTTPS origin such as https://api.xgate.run");
|
|
21402
|
-
var BaseBatchChannelRailSchema = z.object({
|
|
21403
|
-
id: ruleId,
|
|
21150
|
+
var InferenceRailProfileSchema = z.object({
|
|
21151
|
+
/** Shown to the user, e.g. `base-mainnet`. */
|
|
21152
|
+
name: z.string().regex(/^[a-z0-9][a-z0-9-]{0,31}$/),
|
|
21404
21153
|
kind: z.literal("base-batch-channel"),
|
|
21154
|
+
origin: z.string().url(),
|
|
21405
21155
|
network: z.enum(["eip155:8453", "eip155:84532"]),
|
|
21406
|
-
|
|
21407
|
-
|
|
21408
|
-
|
|
21409
|
-
|
|
21156
|
+
scheme: z.literal("batch-settlement"),
|
|
21157
|
+
asset: address,
|
|
21158
|
+
assetSymbol: z.literal("USDC"),
|
|
21159
|
+
assetDecimals: z.literal(6),
|
|
21410
21160
|
receiver: address,
|
|
21411
21161
|
receiverAuthorizer: address,
|
|
21412
|
-
|
|
21413
|
-
/**
|
|
21414
|
-
|
|
21415
|
-
|
|
21416
|
-
|
|
21417
|
-
depositAmount: atomic2.optional(),
|
|
21418
|
-
policyRuleId: ruleId.optional()
|
|
21162
|
+
withdrawDelaySeconds: z.number().int().positive().max(31536e3),
|
|
21163
|
+
/** The environment variable the x402 policy names for this network's RPC URL. */
|
|
21164
|
+
rpcUrlEnv: z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),
|
|
21165
|
+
/** Local devnet only: let the payer reach a loopback origin. */
|
|
21166
|
+
allowPrivateNetwork: z.boolean().default(false)
|
|
21419
21167
|
}).strict();
|
|
21420
|
-
var
|
|
21421
|
-
|
|
21422
|
-
|
|
21423
|
-
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
21428
|
-
|
|
21429
|
-
|
|
21430
|
-
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
|
|
21439
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21168
|
+
var BASE_MAINNET_PROFILE = {
|
|
21169
|
+
name: "base-mainnet",
|
|
21170
|
+
kind: "base-batch-channel",
|
|
21171
|
+
origin: "https://api.xgate.run",
|
|
21172
|
+
network: BASE_MAINNET,
|
|
21173
|
+
scheme: "batch-settlement",
|
|
21174
|
+
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
21175
|
+
assetSymbol: "USDC",
|
|
21176
|
+
assetDecimals: 6,
|
|
21177
|
+
withdrawDelaySeconds: 900,
|
|
21178
|
+
rpcUrlEnv: "BASE_RPC_URL",
|
|
21179
|
+
allowPrivateNetwork: false
|
|
21180
|
+
};
|
|
21181
|
+
var STAGING_PROFILE = {
|
|
21182
|
+
name: "staging",
|
|
21183
|
+
kind: "base-batch-channel",
|
|
21184
|
+
origin: "https://devnet-api.xgate.run",
|
|
21185
|
+
network: "eip155:84532",
|
|
21186
|
+
scheme: "batch-settlement",
|
|
21187
|
+
asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
21188
|
+
assetSymbol: "USDC",
|
|
21189
|
+
assetDecimals: 6,
|
|
21190
|
+
receiver: "0x11E5BA3a2593c44d6d180054A4c8aa839202B8dd",
|
|
21191
|
+
receiverAuthorizer: "0x3721824a31197dcDD2984cF43b92B6cc8A87c0Fb",
|
|
21192
|
+
withdrawDelaySeconds: 3600,
|
|
21193
|
+
rpcUrlEnv: "BASE_SEPOLIA_RPC_URL",
|
|
21194
|
+
allowPrivateNetwork: false
|
|
21195
|
+
};
|
|
21196
|
+
var RAIL_PROFILES = {
|
|
21197
|
+
[BASE_MAINNET_PROFILE.name]: BASE_MAINNET_PROFILE,
|
|
21198
|
+
[STAGING_PROFILE.name]: STAGING_PROFILE
|
|
21199
|
+
};
|
|
21200
|
+
var NETWORK_NAMES = {
|
|
21201
|
+
"eip155:8453": "Base",
|
|
21202
|
+
"eip155:84532": "Base Sepolia (testnet)"
|
|
21203
|
+
};
|
|
21204
|
+
function unavailable(message) {
|
|
21205
|
+
return new AgentLaunchError("inference_rail_unavailable", `${message}. Nothing was written.`);
|
|
21206
|
+
}
|
|
21207
|
+
function isLoopbackOrigin(origin) {
|
|
21208
|
+
const host = new URL(origin).hostname;
|
|
21209
|
+
return host === "localhost" || host === "[::1]" || /^127(\.\d{1,3}){3}$/.test(host);
|
|
21210
|
+
}
|
|
21211
|
+
function pinnedProfile(name) {
|
|
21212
|
+
const pinned = Object.hasOwn(RAIL_PROFILES, name) ? RAIL_PROFILES[name] : void 0;
|
|
21213
|
+
if (!pinned) {
|
|
21214
|
+
throw unavailable(
|
|
21215
|
+
`${AGENT_RAIL_PROFILE_ENV} names ${JSON.stringify(name)}, which is not a rail profile this CLI ships (${Object.keys(RAIL_PROFILES).join(", ")})`
|
|
21216
|
+
);
|
|
21448
21217
|
}
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21218
|
+
const parsed = InferenceRailProfileSchema.safeParse(pinned);
|
|
21219
|
+
if (!parsed.success) {
|
|
21220
|
+
throw unavailable(
|
|
21221
|
+
`The ${name} inference channel for taskmarket agent is not published yet, so there is nothing to approve`
|
|
21222
|
+
);
|
|
21223
|
+
}
|
|
21224
|
+
return parsed.data;
|
|
21452
21225
|
}
|
|
21453
|
-
async function
|
|
21226
|
+
async function customProfile(file) {
|
|
21454
21227
|
let raw;
|
|
21455
21228
|
try {
|
|
21456
|
-
raw = await fs2.readFile(
|
|
21229
|
+
raw = JSON.parse(await fs2.readFile(file, "utf8"));
|
|
21457
21230
|
} catch (error) {
|
|
21458
|
-
|
|
21231
|
+
throw unavailable(
|
|
21232
|
+
`${AGENT_RAIL_PROFILE_FILE_ENV} names ${file}, which could not be read as JSON: ${error.message}`
|
|
21233
|
+
);
|
|
21234
|
+
}
|
|
21235
|
+
const parsed = InferenceRailProfileSchema.safeParse(raw);
|
|
21236
|
+
if (!parsed.success) {
|
|
21237
|
+
const issue = parsed.error.issues[0];
|
|
21238
|
+
throw unavailable(`${file}: ${issue.path.join(".") || "(root)"}: ${issue.message}`);
|
|
21239
|
+
}
|
|
21240
|
+
const profile = parsed.data;
|
|
21241
|
+
if (profile.network === BASE_MAINNET) {
|
|
21242
|
+
throw unavailable(
|
|
21243
|
+
`${file}: a custom rail profile cannot use Base mainnet (${BASE_MAINNET}); mainnet terms are pinned in the CLI`
|
|
21244
|
+
);
|
|
21245
|
+
}
|
|
21246
|
+
if (Object.hasOwn(RAIL_PROFILES, profile.name)) {
|
|
21247
|
+
throw unavailable(`${file}: the name ${profile.name} belongs to a pinned rail profile`);
|
|
21248
|
+
}
|
|
21249
|
+
const url = new URL(profile.origin);
|
|
21250
|
+
if (url.protocol !== "https:" || url.origin !== profile.origin) {
|
|
21251
|
+
throw unavailable(`${file}: origin must be an HTTPS origin with nothing after it`);
|
|
21252
|
+
}
|
|
21253
|
+
if (profile.allowPrivateNetwork && !isLoopbackOrigin(profile.origin)) {
|
|
21254
|
+
throw unavailable(
|
|
21255
|
+
`${file}: allowPrivateNetwork is only for a local devnet, whose origin is a loopback address`
|
|
21256
|
+
);
|
|
21257
|
+
}
|
|
21258
|
+
return profile;
|
|
21259
|
+
}
|
|
21260
|
+
async function loadInferenceRailProfile(env = process.env) {
|
|
21261
|
+
const name = env[AGENT_RAIL_PROFILE_ENV]?.trim();
|
|
21262
|
+
const file = env[AGENT_RAIL_PROFILE_FILE_ENV]?.trim();
|
|
21263
|
+
if (!file) return pinnedProfile(name || BASE_MAINNET_PROFILE.name);
|
|
21264
|
+
if (name) {
|
|
21265
|
+
throw unavailable(
|
|
21266
|
+
`Set either ${AGENT_RAIL_PROFILE_ENV} (a pinned profile) or ${AGENT_RAIL_PROFILE_FILE_ENV} (a development profile), not both`
|
|
21267
|
+
);
|
|
21268
|
+
}
|
|
21269
|
+
if (env[AGENT_DEVELOPER_ENV]?.trim() !== "1") {
|
|
21270
|
+
throw unavailable(
|
|
21271
|
+
`${AGENT_RAIL_PROFILE_FILE_ENV} is a development setting and is read only with ${AGENT_DEVELOPER_ENV}=1; set ${AGENT_RAIL_PROFILE_ENV} to a pinned profile (${Object.keys(RAIL_PROFILES).join(", ")}) instead`
|
|
21272
|
+
);
|
|
21273
|
+
}
|
|
21274
|
+
return customProfile(file);
|
|
21275
|
+
}
|
|
21276
|
+
|
|
21277
|
+
// src/lib/agent/onboarding.ts
|
|
21278
|
+
var ONBOARDING_DEFAULTS = {
|
|
21279
|
+
depositUsd: "5",
|
|
21280
|
+
perRequestUsd: "1",
|
|
21281
|
+
/** The total defaults to this many deposits. */
|
|
21282
|
+
totalDeposits: 2n,
|
|
21283
|
+
expiryDays: 30,
|
|
21284
|
+
computePerDayUsd: "10",
|
|
21285
|
+
computePerMonthUsd: "20",
|
|
21286
|
+
autoTopUpChunksPerDay: 1
|
|
21287
|
+
};
|
|
21288
|
+
var MAX_EXPIRY_DAYS = 365;
|
|
21289
|
+
var MAX_ATTEMPTS = 5;
|
|
21290
|
+
var DAY_MS = 864e5;
|
|
21291
|
+
function rate(value) {
|
|
21292
|
+
const r = value;
|
|
21293
|
+
if (typeof r?.numerator !== "string" || !/^\d{1,13}$/.test(r.numerator)) return void 0;
|
|
21294
|
+
if (!Number.isSafeInteger(r.denominator) || r.denominator <= 0) return void 0;
|
|
21295
|
+
return Number(r.numerator) / r.denominator;
|
|
21296
|
+
}
|
|
21297
|
+
async function readXgateCatalog(origin, fetchImpl = fetch) {
|
|
21298
|
+
const response = await fetchImpl(`${origin}/v1/models`, {
|
|
21299
|
+
signal: AbortSignal.timeout(15e3),
|
|
21300
|
+
redirect: "error",
|
|
21301
|
+
headers: { accept: "application/json" }
|
|
21302
|
+
});
|
|
21303
|
+
if (!response.ok) throw new Error(`the model catalog answered ${response.status}`);
|
|
21304
|
+
const body = await response.json();
|
|
21305
|
+
if (!Array.isArray(body.data)) throw new Error("the model catalog is malformed");
|
|
21306
|
+
const models = [];
|
|
21307
|
+
for (const row of body.data.slice(0, 128)) {
|
|
21308
|
+
const id = row?.id;
|
|
21309
|
+
if (typeof id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(id)) continue;
|
|
21310
|
+
const rates = row.execution_profile?.rates;
|
|
21311
|
+
if (!rates) continue;
|
|
21312
|
+
models.push({
|
|
21313
|
+
id,
|
|
21314
|
+
route: routeOfCatalogRow(row),
|
|
21315
|
+
inputUsdPerMTok: rate(rates["input_uncached"]),
|
|
21316
|
+
outputUsdPerMTok: rate(rates["output"])
|
|
21317
|
+
});
|
|
21318
|
+
}
|
|
21319
|
+
return models;
|
|
21320
|
+
}
|
|
21321
|
+
var CHAIN_IDS = {
|
|
21322
|
+
"eip155:8453": 8453,
|
|
21323
|
+
"eip155:84532": 84532
|
|
21324
|
+
};
|
|
21325
|
+
async function readBaseChain(profile, rpcUrl, wallet) {
|
|
21326
|
+
const client = createPublicClient({
|
|
21327
|
+
transport: http(rpcUrl, { timeout: 15e3, retryCount: 1 })
|
|
21328
|
+
});
|
|
21329
|
+
const chainId = await client.getChainId();
|
|
21330
|
+
if (chainId !== CHAIN_IDS[profile.network]) {
|
|
21331
|
+
throw new Error(`the RPC serves chain ${chainId}, not ${profile.network}`);
|
|
21332
|
+
}
|
|
21333
|
+
const blockNumber = await client.getBlockNumber();
|
|
21334
|
+
let usdcBalance;
|
|
21335
|
+
try {
|
|
21336
|
+
usdcBalance = await client.readContract({
|
|
21337
|
+
address: profile.asset,
|
|
21338
|
+
abi: erc20Abi,
|
|
21339
|
+
functionName: "balanceOf",
|
|
21340
|
+
args: [wallet]
|
|
21341
|
+
});
|
|
21342
|
+
} catch {
|
|
21343
|
+
}
|
|
21344
|
+
return { blockNumber, usdcBalance };
|
|
21345
|
+
}
|
|
21346
|
+
function defaultDeps() {
|
|
21347
|
+
return {
|
|
21348
|
+
now: () => /* @__PURE__ */ new Date(),
|
|
21349
|
+
loadProfile: () => loadInferenceRailProfile(),
|
|
21350
|
+
readCatalog: (origin) => readXgateCatalog(origin),
|
|
21351
|
+
readChain: readBaseChain,
|
|
21352
|
+
computePricing: fetchComputePricing,
|
|
21353
|
+
computeBalance: readComputeCreditBalance,
|
|
21354
|
+
computeConfig: loadComputeCreditConfig,
|
|
21355
|
+
async computeSetUp(input, pricing) {
|
|
21356
|
+
const plan = await planComputeCreditSetup(input, pricing);
|
|
21357
|
+
return applyComputeCreditSetup(
|
|
21358
|
+
plan,
|
|
21359
|
+
`Approved at the terminal by the device owner during taskmarket agent setup: compute credit caps $${plan.caps.perDayUsd}/day, $${plan.caps.perMonthUsd}/month, $${plan.caps.totalUsd} total${plan.autoTopUp ? `; auto-top-up $${plan.autoTopUp.amountUsd} below ${plan.autoTopUp.thresholdCredits} credits, at most ${plan.autoTopUp.maxChunksPerDay}/day` : ""}`
|
|
21360
|
+
);
|
|
21361
|
+
},
|
|
21362
|
+
async computeBuy(amountUsd) {
|
|
21363
|
+
const bought = await buyComputeCredit({ amountUsd });
|
|
21364
|
+
return { credits: bought.purchase.credits };
|
|
21365
|
+
},
|
|
21366
|
+
randomSalt: () => `0x${randomBytes(32).toString("hex")}`,
|
|
21367
|
+
env: process.env
|
|
21368
|
+
};
|
|
21369
|
+
}
|
|
21370
|
+
var usd = (atomic) => `$${atomicToUsd(String(atomic))}`;
|
|
21371
|
+
function tooManyAnswers() {
|
|
21372
|
+
return new AgentLaunchError(
|
|
21373
|
+
"setup_cancelled",
|
|
21374
|
+
"Setup was cancelled after too many answers that could not be used; nothing more was written"
|
|
21375
|
+
);
|
|
21376
|
+
}
|
|
21377
|
+
async function askUsd(prompter, question, fallbackAtomic, check = () => void 0) {
|
|
21378
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
21379
|
+
const answer = (await prompter.ask(question, usd(fallbackAtomic))).replace(/^\$/, "");
|
|
21380
|
+
let atomic;
|
|
21381
|
+
try {
|
|
21382
|
+
atomic = usdToAtomic(answer);
|
|
21383
|
+
} catch {
|
|
21384
|
+
prompter.say([` Not a dollar amount above zero: ${answer}`]);
|
|
21385
|
+
continue;
|
|
21386
|
+
}
|
|
21387
|
+
const problem = check(BigInt(atomic));
|
|
21388
|
+
if (problem) {
|
|
21389
|
+
prompter.say([` ${problem}`]);
|
|
21390
|
+
continue;
|
|
21391
|
+
}
|
|
21392
|
+
return atomic;
|
|
21393
|
+
}
|
|
21394
|
+
throw tooManyAnswers();
|
|
21395
|
+
}
|
|
21396
|
+
async function askWhole(prompter, question, fallback, min, max) {
|
|
21397
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
21398
|
+
const answer = await prompter.ask(question, String(fallback));
|
|
21399
|
+
if (/^\d{1,6}$/.test(answer) && Number(answer) >= min && Number(answer) <= max) {
|
|
21400
|
+
return Number(answer);
|
|
21401
|
+
}
|
|
21402
|
+
prompter.say([` Enter a whole number from ${min} to ${max}`]);
|
|
21403
|
+
}
|
|
21404
|
+
throw tooManyAnswers();
|
|
21405
|
+
}
|
|
21406
|
+
async function askYesNo(prompter, question, fallback) {
|
|
21407
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
21408
|
+
const answer = (await prompter.ask(question, fallback ? "yes" : "no")).toLowerCase();
|
|
21409
|
+
if (answer === "yes" || answer === "y") return true;
|
|
21410
|
+
if (answer === "no" || answer === "n") return false;
|
|
21411
|
+
prompter.say([" Answer yes or no"]);
|
|
21412
|
+
}
|
|
21413
|
+
throw tooManyAnswers();
|
|
21414
|
+
}
|
|
21415
|
+
function duration(seconds) {
|
|
21416
|
+
if (seconds % 3600 === 0) return `${seconds / 3600} hour${seconds === 3600 ? "" : "s"}`;
|
|
21417
|
+
if (seconds % 60 === 0) return `${seconds / 60} minutes`;
|
|
21418
|
+
return `${seconds} seconds`;
|
|
21419
|
+
}
|
|
21420
|
+
function price(value) {
|
|
21421
|
+
return value === void 0 ? "unlisted" : `$${Number(value.toPrecision(6))}`;
|
|
21422
|
+
}
|
|
21423
|
+
function termsLines(profile, wallet, models, chain) {
|
|
21424
|
+
return [
|
|
21425
|
+
"",
|
|
21426
|
+
"Inference terms",
|
|
21427
|
+
` Wallet: ${wallet} (its key stays in the keystore and is never asked for)`,
|
|
21428
|
+
...chain.usdcBalance !== void 0 ? [` Balance: ${usd(chain.usdcBalance)} ${profile.assetSymbol}`] : [],
|
|
21429
|
+
` Origin: ${profile.origin}`,
|
|
21430
|
+
` Network: ${NETWORK_NAMES[profile.network]} (${profile.network})`,
|
|
21431
|
+
` Asset: ${profile.assetSymbol} ${profile.asset}`,
|
|
21432
|
+
` Receiver: ${profile.receiver} (authorizer ${profile.receiverAuthorizer})`,
|
|
21433
|
+
` Scheme: ${profile.scheme}, profile ${profile.name}`,
|
|
21434
|
+
" Models and prices, per million tokens. Each turn is charged its actual usage, at most",
|
|
21435
|
+
" the per-request limit:",
|
|
21436
|
+
...models.map(
|
|
21437
|
+
(model) => ` ${model.id}: input ${price(model.inputUsdPerMTok)}, output ${price(model.outputUsdPerMTok)}`
|
|
21438
|
+
)
|
|
21439
|
+
];
|
|
21440
|
+
}
|
|
21441
|
+
function channelLines(profile, routes, limits, usedSoFar, blocked) {
|
|
21442
|
+
const windows = depositWindows(limits.total, routes);
|
|
21443
|
+
return [
|
|
21444
|
+
"",
|
|
21445
|
+
`Inference channel (x402 ${profile.scheme} on ${NETWORK_NAMES[profile.network]})`,
|
|
21446
|
+
" - Your deposit is the session budget. It is locked in escrow in the channel contract, not",
|
|
21447
|
+
" paid to anyone; each turn signs an off-chain voucher for what the turn actually used.",
|
|
21448
|
+
" - The deposit is gasless: it travels with your first paid turn and the facilitator pays its",
|
|
21449
|
+
" gas. Setup itself deposits nothing and buys nothing.",
|
|
21450
|
+
` - Unused funds are refundable: a cooperative refund returns them at once, or a withdrawal`,
|
|
21451
|
+
` returns them after the channel's withdraw delay of ${duration(profile.withdrawDelaySeconds)}.`,
|
|
21452
|
+
" - When the deposit runs low it is topped up to the deposit amount, never past the total.",
|
|
21453
|
+
` - Channels: ${routes.length} (${routes.join(", ")}); each has its own deposit, and all of`,
|
|
21454
|
+
" them together spend at most the total.",
|
|
21455
|
+
` Deposit (session budget): ${usd(limits.deposit)} a channel`,
|
|
21456
|
+
` Per-request limit: ${usd(limits.perRequest)}`,
|
|
21457
|
+
` Total limit: ${usd(limits.total)} for all channels together, for the life of the budget${usedSoFar > 0n ? `, including ${usd(usedSoFar)} already used (history is kept)` : ""}`,
|
|
21458
|
+
...routes.length > 1 ? [
|
|
21459
|
+
` Deposits a day: at most ${routes.map((route) => `${usd(windows.get(route))} into ${slug(route)}`).join(", ")}, the total split between the channels`
|
|
21460
|
+
] : [` Deposits a day: at most ${usd(limits.total)}`],
|
|
21461
|
+
` Expires: ${limits.expiresAt}`,
|
|
21462
|
+
...blocked ? [
|
|
21463
|
+
` Note: today's deposit limit is used, so the first turn${blocked.resetsAt ? ` cannot deposit until ${utc(blocked.resetsAt)}` : " cannot deposit yet"} (a total of at least ${usd(blocked.minimumTotal)} would fit today).`
|
|
21464
|
+
] : []
|
|
21465
|
+
];
|
|
21466
|
+
}
|
|
21467
|
+
var utc = (iso) => iso.replace("T", " ").replace(/Z$/, " UTC");
|
|
21468
|
+
function depositWindowLines(check, limits) {
|
|
21469
|
+
return [
|
|
21470
|
+
"",
|
|
21471
|
+
"Today's deposit limit is used",
|
|
21472
|
+
...check.blocks.map(
|
|
21473
|
+
(block) => ` - ${slug(block.route)}: ${usd(block.used)} of its ${usd(block.window)} daily deposit limit is already used, so the new channel's first ${usd(block.deposit)} deposit does not fit.`
|
|
21474
|
+
),
|
|
21475
|
+
" Deposits count against the limit for 24 hours, even once refunded, so closing a channel",
|
|
21476
|
+
" does not free it.",
|
|
21477
|
+
check.resetsAt ? ` The limit resets at ${utc(check.resetsAt)}. Until then the first turn is refused (policy_denied).` : " A deposit or purchase whose outcome is unknown counts in full until it is reconciled",
|
|
21478
|
+
...check.resetsAt ? [] : [
|
|
21479
|
+
" (see taskmarket agent status), so waiting alone does not free the limit. Until then the",
|
|
21480
|
+
" first turn is refused (policy_denied)."
|
|
21481
|
+
],
|
|
21482
|
+
" Either:",
|
|
21483
|
+
` - raise the total to at least ${usd(check.minimumTotal)} (from ${usd(limits.total)}): the daily limit is a share of the total; or`,
|
|
21484
|
+
check.resetsAt ? ` - keep ${usd(limits.total)} and start the first turn after ${utc(check.resetsAt)}.` : ` - keep ${usd(limits.total)} and reconcile the unknown outcome first.`
|
|
21485
|
+
];
|
|
21486
|
+
}
|
|
21487
|
+
var WORKSPACE_LINES = [
|
|
21488
|
+
"",
|
|
21489
|
+
"Remote workspace",
|
|
21490
|
+
" - Every tool the agent uses (read, write, edit, bash, grep, find, ls and your ! commands)",
|
|
21491
|
+
" runs in a Boat cloud VM in the EU, never on this machine. The VM holds no wallet key or",
|
|
21492
|
+
" credential, and it has open internet egress.",
|
|
21493
|
+
" - Uploaded: your project's git-tracked files and untracked files you select, respecting",
|
|
21494
|
+
" .gitignore. Secret-like files (.env*, private keys, credentials) are excluded unless you",
|
|
21495
|
+
" include them yourself. Changes come back only as a diff you review. Until workspace sync",
|
|
21496
|
+
" ships, the sandbox starts empty and nothing is uploaded.",
|
|
21497
|
+
" - Retention: Boat snapshots the workspace every minute while the VM runs and keeps the",
|
|
21498
|
+
" snapshots for the life of the sandbox; deleting the sandbox removes the snapshots only it",
|
|
21499
|
+
" uses. Boat keeps machine-assignment, IP and billing records."
|
|
21500
|
+
];
|
|
21501
|
+
function computeRateLines(pricing, availableCredits) {
|
|
21502
|
+
return [
|
|
21503
|
+
"",
|
|
21504
|
+
"Compute credit (pays for the sandbox VM, separately from inference)",
|
|
21505
|
+
...pricing.machineTypes.map(
|
|
21506
|
+
(machine) => ` ${machine.machineType} sandbox: $${machine.usdPerHour} an hour while it runs (${machine.creditsPerHour} credits), nothing while stopped`
|
|
21507
|
+
),
|
|
21508
|
+
` The rate is the provider's cost times ${pricing.markup}; $${pricing.usdPerCredit} a credit (rate card ${pricing.rateCardVersion}${pricing.salesApproval === "approved" ? "" : ", not yet approved for live sales"})`,
|
|
21509
|
+
` Available: ${availableCredits} credits`
|
|
21510
|
+
];
|
|
21511
|
+
}
|
|
21512
|
+
function slug(route) {
|
|
21513
|
+
return route.split("/")[2];
|
|
21514
|
+
}
|
|
21515
|
+
function shortId() {
|
|
21516
|
+
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
21517
|
+
}
|
|
21518
|
+
async function preflight(deps, profile, wallet, prompter) {
|
|
21519
|
+
prompter.say(["", "Checking the inference terms, the chain and compute (read-only)..."]);
|
|
21520
|
+
const step = async (name, read) => {
|
|
21521
|
+
try {
|
|
21522
|
+
return await read();
|
|
21523
|
+
} catch (error) {
|
|
21524
|
+
if (error instanceof AgentLaunchError) throw error;
|
|
21459
21525
|
throw new AgentLaunchError(
|
|
21460
|
-
"
|
|
21461
|
-
`
|
|
21526
|
+
"preflight_failed",
|
|
21527
|
+
`Setup could not read ${name}: ${error.message}. Nothing was written.`,
|
|
21528
|
+
{ check: name }
|
|
21462
21529
|
);
|
|
21463
21530
|
}
|
|
21531
|
+
};
|
|
21532
|
+
const x402Policy = await step(
|
|
21533
|
+
"the x402 policy",
|
|
21534
|
+
() => loadX402Policy(getX402PolicyPath(), { allowMissing: true })
|
|
21535
|
+
);
|
|
21536
|
+
const rpcUrlEnv = x402Policy.networks[profile.network]?.rpcUrlEnv ?? profile.rpcUrlEnv;
|
|
21537
|
+
const rpcUrl = deps.env[rpcUrlEnv]?.trim();
|
|
21538
|
+
if (!rpcUrl) {
|
|
21539
|
+
throw new AgentLaunchError(
|
|
21540
|
+
"preflight_failed",
|
|
21541
|
+
`Set ${rpcUrlEnv} to a ${NETWORK_NAMES[profile.network]} RPC URL; the channel's deposits and refunds are checked on chain. Nothing was written.`,
|
|
21542
|
+
{ check: "rpc" }
|
|
21543
|
+
);
|
|
21544
|
+
}
|
|
21545
|
+
const models = await step("the xgate model catalog", () => deps.readCatalog(profile.origin));
|
|
21546
|
+
if (models.length === 0) {
|
|
21547
|
+
throw new AgentLaunchError(
|
|
21548
|
+
"no_qualified_models",
|
|
21549
|
+
`xgate at ${profile.origin} offers no model a channel can pay for`
|
|
21550
|
+
);
|
|
21551
|
+
}
|
|
21552
|
+
const chain = await step("the chain", () => deps.readChain(profile, rpcUrl, wallet));
|
|
21553
|
+
const pricing = await step("the compute pricing", () => deps.computePricing());
|
|
21554
|
+
const availableCredits = await step("the compute credit balance", () => deps.computeBalance());
|
|
21555
|
+
return { x402Policy, rpcUrlEnv, rpcUrl, models, chain, pricing, availableCredits };
|
|
21556
|
+
}
|
|
21557
|
+
function totalRules(input) {
|
|
21558
|
+
const { deposit, perRequest, previousTotal, usedSoFar, channels } = input;
|
|
21559
|
+
const sharedFloor = BigInt(deposit) * BigInt(channels);
|
|
21560
|
+
const floor = [sharedFloor, previousTotal, usedSoFar + BigInt(perRequest)].reduce(
|
|
21561
|
+
(a, b) => a > b ? a : b
|
|
21562
|
+
);
|
|
21563
|
+
const problem = (value) => {
|
|
21564
|
+
if (value < BigInt(deposit)) return "The total must be at least the deposit";
|
|
21565
|
+
if (value < sharedFloor) {
|
|
21566
|
+
return `The ${channels} channels share the total, and each needs room for one deposit a day, so it must be at least ${usd(sharedFloor)}`;
|
|
21567
|
+
}
|
|
21568
|
+
if (value < previousTotal) return `The total can only go up from ${usd(previousTotal)}`;
|
|
21569
|
+
if (value < usedSoFar + BigInt(perRequest)) {
|
|
21570
|
+
return `The total must leave room for one request after the ${usd(usedSoFar)} already used`;
|
|
21571
|
+
}
|
|
21572
|
+
return void 0;
|
|
21573
|
+
};
|
|
21574
|
+
return { floor, problem };
|
|
21575
|
+
}
|
|
21576
|
+
async function askLimits(prompter, previous, usedSoFar, exhausted, now, channels) {
|
|
21577
|
+
prompter.say([
|
|
21578
|
+
"",
|
|
21579
|
+
previous ? "Renew the inference limits (amounts in USD; Enter keeps the value shown)" : "Inference limits (amounts in USD; Enter keeps the value shown)"
|
|
21580
|
+
]);
|
|
21581
|
+
const deposit = await askUsd(
|
|
21582
|
+
prompter,
|
|
21583
|
+
"Deposit, the session budget locked in escrow",
|
|
21584
|
+
previous?.limits.deposit ?? usdToAtomic(ONBOARDING_DEFAULTS.depositUsd)
|
|
21585
|
+
);
|
|
21586
|
+
const perRequestFallback = previous?.limits.perRequest ?? usdToAtomic(ONBOARDING_DEFAULTS.perRequestUsd);
|
|
21587
|
+
const perRequest = await askUsd(
|
|
21588
|
+
prompter,
|
|
21589
|
+
"Per-request limit, the most one turn may cost",
|
|
21590
|
+
BigInt(perRequestFallback) > BigInt(deposit) ? deposit : perRequestFallback,
|
|
21591
|
+
(value) => value > BigInt(deposit) ? "The per-request limit must fit in the deposit" : void 0
|
|
21592
|
+
);
|
|
21593
|
+
const previousTotal = previous ? BigInt(previous.limits.total) : 0n;
|
|
21594
|
+
const { floor, problem } = totalRules({
|
|
21595
|
+
deposit,
|
|
21596
|
+
perRequest,
|
|
21597
|
+
previousTotal,
|
|
21598
|
+
usedSoFar,
|
|
21599
|
+
channels
|
|
21600
|
+
});
|
|
21601
|
+
let totalFallback = previous ? previousTotal + (exhausted ? BigInt(deposit) : 0n) : BigInt(deposit) * ONBOARDING_DEFAULTS.totalDeposits;
|
|
21602
|
+
if (totalFallback < floor) totalFallback = floor;
|
|
21603
|
+
const total = await askUsd(
|
|
21604
|
+
prompter,
|
|
21605
|
+
previous ? `Total limit, the most this budget may ever spend (${usd(usedSoFar)} used so far)` : "Total limit, the most this budget may ever spend",
|
|
21606
|
+
String(totalFallback),
|
|
21607
|
+
problem
|
|
21608
|
+
);
|
|
21609
|
+
const days = await askWhole(
|
|
21610
|
+
prompter,
|
|
21611
|
+
"Expires after how many days",
|
|
21612
|
+
ONBOARDING_DEFAULTS.expiryDays,
|
|
21613
|
+
1,
|
|
21614
|
+
MAX_EXPIRY_DAYS
|
|
21615
|
+
);
|
|
21616
|
+
return {
|
|
21617
|
+
perRequest,
|
|
21618
|
+
deposit,
|
|
21619
|
+
total,
|
|
21620
|
+
expiresAt: new Date(now.getTime() + days * DAY_MS).toISOString()
|
|
21621
|
+
};
|
|
21622
|
+
}
|
|
21623
|
+
function sameTerms(rail, profile, wallet) {
|
|
21624
|
+
const same = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
21625
|
+
return rail.origin === profile.origin && rail.network === profile.network && same(rail.asset, profile.asset) && same(rail.receiver, profile.receiver) && same(rail.receiverAuthorizer, profile.receiverAuthorizer) && same(rail.wallet, wallet);
|
|
21626
|
+
}
|
|
21627
|
+
function channelSessionKey(rail, rpcUrl, journalPath) {
|
|
21628
|
+
const channel = {
|
|
21629
|
+
network: rail.network,
|
|
21630
|
+
payer: rail.wallet,
|
|
21631
|
+
receiver: rail.receiver,
|
|
21632
|
+
receiverAuthorizer: rail.receiverAuthorizer,
|
|
21633
|
+
salt: rail.salt
|
|
21634
|
+
};
|
|
21635
|
+
return createBaseChannelPayer({
|
|
21636
|
+
channel,
|
|
21637
|
+
reader: createBaseChannelRpcReader({ channel, rpcUrl, fromBlock: BigInt(rail.fromBlock) }),
|
|
21638
|
+
resourceUrl: `${rail.origin}${rail.route}`,
|
|
21639
|
+
journalPath,
|
|
21640
|
+
loadPolicy: (options) => loadX402Policy(getX402PolicyPath(), options),
|
|
21641
|
+
getAccount: async () => {
|
|
21642
|
+
throw new Error("onboarding never signs");
|
|
21643
|
+
},
|
|
21644
|
+
allocationId: rail.allocationId,
|
|
21645
|
+
budgetAmount: rail.limits.total,
|
|
21646
|
+
depositAmount: rail.limits.deposit,
|
|
21647
|
+
policyRuleId: rail.policyRuleId
|
|
21648
|
+
}).sessionKey;
|
|
21649
|
+
}
|
|
21650
|
+
function ruleFor(rail, profile, depositWindow) {
|
|
21651
|
+
return {
|
|
21652
|
+
id: rail.policyRuleId,
|
|
21653
|
+
enabled: true,
|
|
21654
|
+
priority: 100,
|
|
21655
|
+
origin: rail.origin,
|
|
21656
|
+
pathPrefix: rail.route,
|
|
21657
|
+
methods: ["POST"],
|
|
21658
|
+
unattended: true,
|
|
21659
|
+
allowPrivateNetwork: profile.allowPrivateNetwork,
|
|
21660
|
+
maxAuthorizationSeconds: 300,
|
|
21661
|
+
payments: [
|
|
21662
|
+
{
|
|
21663
|
+
scheme: rail.scheme,
|
|
21664
|
+
network: rail.network,
|
|
21665
|
+
asset: rail.asset,
|
|
21666
|
+
payTo: rail.receiver,
|
|
21667
|
+
displaySymbol: profile.assetSymbol,
|
|
21668
|
+
displayDecimals: profile.assetDecimals,
|
|
21669
|
+
maxPerPayment: rail.limits.perRequest,
|
|
21670
|
+
// Each deposit and top-up counts against this window once (ADR-0236). The rails' windows
|
|
21671
|
+
// split the total, so together they admit at most the total in a day.
|
|
21672
|
+
spendWindow: { seconds: 86400, max: depositWindow }
|
|
21673
|
+
}
|
|
21674
|
+
]
|
|
21675
|
+
};
|
|
21676
|
+
}
|
|
21677
|
+
async function openBudgetCap(store, id) {
|
|
21678
|
+
try {
|
|
21679
|
+
const budget = await store.get(id);
|
|
21680
|
+
return budget.allocation.closedAt ? void 0 : budget.allocation.caps.amount;
|
|
21681
|
+
} catch (error) {
|
|
21682
|
+
if (error.code === "allocation_not_found") return void 0;
|
|
21464
21683
|
throw error;
|
|
21465
21684
|
}
|
|
21466
|
-
|
|
21685
|
+
}
|
|
21686
|
+
async function openBudget(store, rail, note) {
|
|
21687
|
+
const cap = await openBudgetCap(store, rail.budgetAllocationId);
|
|
21688
|
+
if (cap !== void 0 && BigInt(cap) < BigInt(rail.limits.total)) {
|
|
21689
|
+
await store.raiseCap({
|
|
21690
|
+
allocationId: rail.budgetAllocationId,
|
|
21691
|
+
caps: { amount: rail.limits.total },
|
|
21692
|
+
note
|
|
21693
|
+
});
|
|
21694
|
+
}
|
|
21695
|
+
if (cap === void 0) {
|
|
21696
|
+
await store.open(
|
|
21697
|
+
{
|
|
21698
|
+
id: rail.budgetAllocationId,
|
|
21699
|
+
kind: "agent_session",
|
|
21700
|
+
exposure: "inference",
|
|
21701
|
+
network: rail.network,
|
|
21702
|
+
asset: rail.asset,
|
|
21703
|
+
caps: { amount: rail.limits.total }
|
|
21704
|
+
},
|
|
21705
|
+
{ note }
|
|
21706
|
+
);
|
|
21707
|
+
}
|
|
21708
|
+
}
|
|
21709
|
+
async function openSession(store, rail, sessionKey) {
|
|
21710
|
+
await store.open({
|
|
21711
|
+
id: rail.allocationId,
|
|
21712
|
+
kind: "agent_session",
|
|
21713
|
+
exposure: "inference",
|
|
21714
|
+
parentId: rail.budgetAllocationId,
|
|
21715
|
+
network: rail.network,
|
|
21716
|
+
asset: rail.asset,
|
|
21717
|
+
caps: { amount: rail.limits.total },
|
|
21718
|
+
funding: { railId: BASE_CHANNEL_RAIL_ID, sessionKey }
|
|
21719
|
+
});
|
|
21720
|
+
}
|
|
21721
|
+
async function computeStep(deps, prompter, pricing, availableCredits, renewing) {
|
|
21722
|
+
if (renewing && Number(availableCredits) > 0) {
|
|
21723
|
+
return { action: "not_offered", availableCredits };
|
|
21724
|
+
}
|
|
21725
|
+
prompter.say(computeRateLines(pricing, availableCredits));
|
|
21726
|
+
const sizes = pricing.denominations.map((entry) => entry.amountUsd);
|
|
21727
|
+
const fallback = (pricing.denominations.find((entry) => entry.default) ?? pricing.denominations[0]).amountUsd;
|
|
21728
|
+
let amountUsd = -1;
|
|
21729
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS && amountUsd < 0; attempt += 1) {
|
|
21730
|
+
const answer = (await prompter.ask(
|
|
21731
|
+
`Buy a first chunk of compute credit in USD: ${sizes.join(", ")}, or 0 for none`,
|
|
21732
|
+
String(fallback)
|
|
21733
|
+
)).replace(/^\$/, "");
|
|
21734
|
+
if (answer === "0" || sizes.map(String).includes(answer)) amountUsd = Number(answer);
|
|
21735
|
+
else prompter.say([` Choose one of ${sizes.join(", ")}, or 0`]);
|
|
21736
|
+
}
|
|
21737
|
+
if (amountUsd < 0) throw tooManyAnswers();
|
|
21738
|
+
let config = await deps.computeConfig();
|
|
21739
|
+
let setup;
|
|
21740
|
+
if (!config) {
|
|
21741
|
+
const autoTopUp = await askYesNo(
|
|
21742
|
+
prompter,
|
|
21743
|
+
"Turn on auto-top-up, buying one chunk when credit runs low",
|
|
21744
|
+
false
|
|
21745
|
+
);
|
|
21746
|
+
if (amountUsd === 0 && !autoTopUp) return { action: "skipped" };
|
|
21747
|
+
const chunk = amountUsd || fallback;
|
|
21748
|
+
const minimumDay = usdToAtomic(String(chunk));
|
|
21749
|
+
const perDay = await askUsd(
|
|
21750
|
+
prompter,
|
|
21751
|
+
"Compute cap: most bought in one UTC day",
|
|
21752
|
+
BigInt(usdToAtomic(ONBOARDING_DEFAULTS.computePerDayUsd)) < BigInt(minimumDay) ? minimumDay : usdToAtomic(ONBOARDING_DEFAULTS.computePerDayUsd),
|
|
21753
|
+
(value) => value < BigInt(minimumDay) ? `The daily cap must cover a $${chunk} chunk` : void 0
|
|
21754
|
+
);
|
|
21755
|
+
const perMonth = await askUsd(
|
|
21756
|
+
prompter,
|
|
21757
|
+
"Compute cap: most bought in one UTC month",
|
|
21758
|
+
BigInt(usdToAtomic(ONBOARDING_DEFAULTS.computePerMonthUsd)) < BigInt(perDay) ? perDay : usdToAtomic(ONBOARDING_DEFAULTS.computePerMonthUsd),
|
|
21759
|
+
(value) => value < BigInt(perDay) ? "The monthly cap must be at least the daily cap" : void 0
|
|
21760
|
+
);
|
|
21761
|
+
setup = { perDayUsd: atomicToUsd(perDay), perMonthUsd: atomicToUsd(perMonth) };
|
|
21762
|
+
if (autoTopUp) {
|
|
21763
|
+
const chunkCredits = pricing.denominations.find((entry) => entry.amountUsd === chunk)?.credits ?? "1";
|
|
21764
|
+
const threshold = await prompter.ask(
|
|
21765
|
+
"Auto-top-up: buy when available credit falls below (credits)",
|
|
21766
|
+
String(Math.max(1, Math.floor(Number(chunkCredits) / 4)))
|
|
21767
|
+
);
|
|
21768
|
+
const maxChunks = await askWhole(
|
|
21769
|
+
prompter,
|
|
21770
|
+
`Auto-top-up: most $${chunk} chunks in one UTC day`,
|
|
21771
|
+
ONBOARDING_DEFAULTS.autoTopUpChunksPerDay,
|
|
21772
|
+
1,
|
|
21773
|
+
Math.max(1, Math.floor(Number(atomicToUsd(perDay)) / chunk))
|
|
21774
|
+
);
|
|
21775
|
+
setup.autoTopUp = {
|
|
21776
|
+
thresholdCredits: threshold,
|
|
21777
|
+
amountUsd: chunk,
|
|
21778
|
+
maxChunksPerDay: maxChunks
|
|
21779
|
+
};
|
|
21780
|
+
}
|
|
21781
|
+
} else if (amountUsd === 0) {
|
|
21782
|
+
return { action: "skipped" };
|
|
21783
|
+
}
|
|
21784
|
+
const credits = pricing.denominations.find((entry) => entry.amountUsd === amountUsd)?.credits;
|
|
21785
|
+
const approved = await prompter.confirm(
|
|
21786
|
+
[
|
|
21787
|
+
"",
|
|
21788
|
+
...setup ? [
|
|
21789
|
+
`Approve a compute allocation capped at $${setup.perDayUsd} a day and $${setup.perMonthUsd} a month${setup.autoTopUp ? `, with auto-top-up of $${setup.autoTopUp.amountUsd} below ${setup.autoTopUp.thresholdCredits} credits, at most ${setup.autoTopUp.maxChunksPerDay} a day` : ""}`
|
|
21790
|
+
] : [],
|
|
21791
|
+
...amountUsd > 0 ? [
|
|
21792
|
+
`Buy $${amountUsd} of compute credit (${credits} credits) now, from your wallet over x402`
|
|
21793
|
+
] : [],
|
|
21794
|
+
""
|
|
21795
|
+
].join("\n")
|
|
21796
|
+
);
|
|
21797
|
+
if (!approved) {
|
|
21798
|
+
prompter.say(["No compute credit was approved or bought."]);
|
|
21799
|
+
return { action: "declined" };
|
|
21800
|
+
}
|
|
21467
21801
|
try {
|
|
21468
|
-
|
|
21469
|
-
|
|
21470
|
-
|
|
21802
|
+
if (setup) {
|
|
21803
|
+
await deps.computeSetUp(setup, pricing);
|
|
21804
|
+
config = await deps.computeConfig();
|
|
21805
|
+
}
|
|
21806
|
+
if (amountUsd === 0) return { action: "skipped" };
|
|
21807
|
+
const bought = await deps.computeBuy(amountUsd);
|
|
21808
|
+
prompter.say([`Bought $${amountUsd} of compute credit (${bought.credits} credits).`]);
|
|
21809
|
+
return { action: "bought", amountUsd, credits: bought.credits };
|
|
21810
|
+
} catch (error) {
|
|
21811
|
+
const code = String(error.code ?? "unknown");
|
|
21812
|
+
const message = error.message;
|
|
21813
|
+
prompter.say([
|
|
21814
|
+
`The compute credit purchase did not complete (${code}): ${message}`,
|
|
21815
|
+
"Your inference policy is saved. Buy credit later with taskmarket agent credits buy."
|
|
21816
|
+
]);
|
|
21817
|
+
return { action: "failed", code, message };
|
|
21471
21818
|
}
|
|
21472
|
-
|
|
21473
|
-
|
|
21474
|
-
|
|
21819
|
+
}
|
|
21820
|
+
async function runOnboarding(input) {
|
|
21821
|
+
const deps = { ...defaultDeps(), ...input.deps };
|
|
21822
|
+
const { prompter, walletAddress: wallet } = input;
|
|
21823
|
+
const previousPolicy = input.renew?.policy;
|
|
21824
|
+
const reasons = input.renew?.assessment.reasons ?? [];
|
|
21825
|
+
prompter.say(
|
|
21826
|
+
previousPolicy ? [
|
|
21827
|
+
"taskmarket agent: your spending policy needs renewal",
|
|
21828
|
+
...reasons.map(
|
|
21829
|
+
({ reason, railId }) => ` - ${railId ? `${railId}: ` : ""}${{
|
|
21830
|
+
expired: "the policy expired",
|
|
21831
|
+
exhausted: "the budget has less left than one request may cost",
|
|
21832
|
+
allocation_unavailable: "its budget allocation is closed or missing",
|
|
21833
|
+
consent_outdated: "the remote workspace terms changed"
|
|
21834
|
+
}[reason]}`
|
|
21835
|
+
),
|
|
21836
|
+
" Renewing keeps the spending history: nothing already used is forgotten."
|
|
21837
|
+
] : [
|
|
21838
|
+
"taskmarket agent: first-run setup",
|
|
21839
|
+
"Nothing is spent until you approve it. The agent pays for inference from a channel you",
|
|
21840
|
+
"fund, and for its cloud sandbox from prepaid compute credit."
|
|
21841
|
+
]
|
|
21842
|
+
);
|
|
21843
|
+
const profile = await deps.loadProfile();
|
|
21844
|
+
const checks = await preflight(deps, profile, wallet, prompter);
|
|
21845
|
+
const models = checks.models.filter((model) => XGATE_ROUTES.includes(model.route));
|
|
21846
|
+
const routes = XGATE_ROUTES.filter((route) => models.some((model) => model.route === route));
|
|
21847
|
+
if (routes.length === 0) {
|
|
21475
21848
|
throw new AgentLaunchError(
|
|
21476
|
-
"
|
|
21477
|
-
|
|
21849
|
+
"no_qualified_models",
|
|
21850
|
+
`xgate at ${profile.origin} offers no model a channel can pay for`
|
|
21478
21851
|
);
|
|
21479
21852
|
}
|
|
21480
|
-
|
|
21853
|
+
prompter.say(termsLines(profile, wallet, models, checks.chain));
|
|
21854
|
+
const now = deps.now();
|
|
21855
|
+
const previousRails = new Map(
|
|
21856
|
+
(previousPolicy?.rails ?? []).filter((rail) => sameTerms(rail, profile, wallet)).map((rail) => [rail.route, rail])
|
|
21857
|
+
);
|
|
21858
|
+
const used = new Map(
|
|
21859
|
+
(input.renew?.assessment.usage ?? []).map((u) => [u.railId, BigInt(u.used)])
|
|
21860
|
+
);
|
|
21861
|
+
const usedSoFar = [...previousRails.values()].reduce((max, rail) => {
|
|
21862
|
+
const value = used.get(rail.id) ?? 0n;
|
|
21863
|
+
return value > max ? value : max;
|
|
21864
|
+
}, 0n);
|
|
21865
|
+
const exhausted = reasons.some((r) => r.reason === "exhausted");
|
|
21866
|
+
const previousRail = previousRails.values().next().value;
|
|
21867
|
+
let limits = await askLimits(prompter, previousRail, usedSoFar, exhausted, now, routes.length);
|
|
21868
|
+
const journalPath = getX402JournalPath();
|
|
21869
|
+
const store = createX402Allocations({
|
|
21870
|
+
journalPath,
|
|
21871
|
+
loadPolicy: (options) => loadX402Policy(getX402PolicyPath(), options)
|
|
21872
|
+
});
|
|
21873
|
+
let budgetAllocationId;
|
|
21874
|
+
for (const rail of previousRails.values()) {
|
|
21875
|
+
if (await openBudgetCap(store, rail.budgetAllocationId) !== void 0) {
|
|
21876
|
+
budgetAllocationId = rail.budgetAllocationId;
|
|
21877
|
+
break;
|
|
21878
|
+
}
|
|
21879
|
+
}
|
|
21880
|
+
budgetAllocationId ??= `agent-inference-${shortId()}`;
|
|
21881
|
+
const openSessions = /* @__PURE__ */ new Set();
|
|
21882
|
+
for (const rail of previousRails.values()) {
|
|
21883
|
+
if (rail.budgetAllocationId === budgetAllocationId && await openBudgetCap(store, rail.allocationId) !== void 0) {
|
|
21884
|
+
openSessions.add(rail.allocationId);
|
|
21885
|
+
}
|
|
21886
|
+
}
|
|
21887
|
+
const keepsChannel = (previous, next) => previous !== void 0 && openSessions.has(previous.allocationId) && previous.limits.deposit === next.deposit && previous.limits.total === next.total;
|
|
21888
|
+
const { floor: totalFloor, problem: totalProblem } = totalRules({
|
|
21889
|
+
deposit: limits.deposit,
|
|
21890
|
+
perRequest: limits.perRequest,
|
|
21891
|
+
previousTotal: previousRail ? BigInt(previousRail.limits.total) : 0n,
|
|
21892
|
+
usedSoFar,
|
|
21893
|
+
channels: routes.length
|
|
21894
|
+
});
|
|
21895
|
+
const windowCheck = (next) => checkDepositWindows({
|
|
21896
|
+
journalPath,
|
|
21897
|
+
now,
|
|
21898
|
+
routes,
|
|
21899
|
+
rails: routes.map((route) => {
|
|
21900
|
+
const previous = previousRails.get(route);
|
|
21901
|
+
const id = previous?.id ?? `xgate-${slug(route)}`;
|
|
21902
|
+
return {
|
|
21903
|
+
railId: id,
|
|
21904
|
+
route,
|
|
21905
|
+
ruleId: previous?.policyRuleId ?? `taskmarket-agent-${id}`,
|
|
21906
|
+
network: profile.network,
|
|
21907
|
+
asset: profile.asset,
|
|
21908
|
+
newChannel: !keepsChannel(previous, next)
|
|
21909
|
+
};
|
|
21910
|
+
}),
|
|
21911
|
+
limits: next,
|
|
21912
|
+
floor: totalFloor
|
|
21913
|
+
});
|
|
21914
|
+
let blocked = await windowCheck(limits);
|
|
21915
|
+
for (let attempt = 0; blocked && attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
21916
|
+
prompter.say(depositWindowLines(blocked, limits));
|
|
21917
|
+
const total = await askUsd(
|
|
21918
|
+
prompter,
|
|
21919
|
+
`Total limit (Enter keeps ${usd(limits.total)}; at least ${usd(blocked.minimumTotal)} fits today)`,
|
|
21920
|
+
limits.total,
|
|
21921
|
+
totalProblem
|
|
21922
|
+
);
|
|
21923
|
+
if (total === limits.total) break;
|
|
21924
|
+
limits = { ...limits, total };
|
|
21925
|
+
blocked = await windowCheck(limits);
|
|
21926
|
+
}
|
|
21927
|
+
prompter.say(channelLines(profile, routes, limits, usedSoFar, blocked));
|
|
21928
|
+
if (!await prompter.confirm("Open the inference channel with these limits?")) {
|
|
21929
|
+
throw new AgentLaunchError(
|
|
21930
|
+
"setup_declined",
|
|
21931
|
+
"The inference channel was not approved. Nothing was written and nothing was bought.",
|
|
21932
|
+
{ step: "channel" }
|
|
21933
|
+
);
|
|
21934
|
+
}
|
|
21935
|
+
const consentCurrent = previousPolicy?.workspace.consentVersion === WORKSPACE_CONSENT_VERSION;
|
|
21936
|
+
if (!consentCurrent) {
|
|
21937
|
+
prompter.say(WORKSPACE_LINES);
|
|
21938
|
+
if (!await prompter.confirm("Use the remote workspace on these terms?")) {
|
|
21939
|
+
throw new AgentLaunchError(
|
|
21940
|
+
"setup_declined",
|
|
21941
|
+
"The remote workspace terms were not accepted, and the agent runs its tools only there. Nothing was written and nothing was bought.",
|
|
21942
|
+
{ step: "workspace" }
|
|
21943
|
+
);
|
|
21944
|
+
}
|
|
21945
|
+
}
|
|
21946
|
+
const rails = routes.map((route) => {
|
|
21947
|
+
const previous = previousRails.get(route);
|
|
21948
|
+
if (previous && keepsChannel(previous, limits)) {
|
|
21949
|
+
return { ...previous, withdrawDelaySeconds: profile.withdrawDelaySeconds, limits };
|
|
21950
|
+
}
|
|
21951
|
+
const id = previous?.id ?? `xgate-${slug(route)}`;
|
|
21952
|
+
return {
|
|
21953
|
+
id,
|
|
21954
|
+
kind: "base-batch-channel",
|
|
21955
|
+
wallet,
|
|
21956
|
+
network: profile.network,
|
|
21957
|
+
scheme: profile.scheme,
|
|
21958
|
+
asset: profile.asset,
|
|
21959
|
+
origin: profile.origin,
|
|
21960
|
+
route,
|
|
21961
|
+
receiver: profile.receiver,
|
|
21962
|
+
receiverAuthorizer: profile.receiverAuthorizer,
|
|
21963
|
+
salt: deps.randomSalt(),
|
|
21964
|
+
fromBlock: checks.chain.blockNumber.toString(),
|
|
21965
|
+
withdrawDelaySeconds: profile.withdrawDelaySeconds,
|
|
21966
|
+
budgetAllocationId,
|
|
21967
|
+
allocationId: `agent-inference-${slug(route)}-${shortId()}`,
|
|
21968
|
+
policyRuleId: previous?.policyRuleId ?? `taskmarket-agent-${id}`,
|
|
21969
|
+
limits
|
|
21970
|
+
};
|
|
21971
|
+
});
|
|
21972
|
+
const retired = (previousPolicy?.rails ?? []).filter(
|
|
21973
|
+
(rail) => !rails.some((next) => next.salt === rail.salt)
|
|
21974
|
+
);
|
|
21975
|
+
const settled = await settledRetiredRails(store, previousPolicy?.retiredRails ?? []);
|
|
21976
|
+
const retiredRails = [
|
|
21977
|
+
...retired,
|
|
21978
|
+
...(previousPolicy?.retiredRails ?? []).filter((rail) => !settled.has(rail.salt))
|
|
21979
|
+
];
|
|
21980
|
+
if (retiredRails.length > MAX_RETIRED_RAILS) {
|
|
21981
|
+
throw new AgentLaunchError(
|
|
21982
|
+
"retired_rails_full",
|
|
21983
|
+
`The policy already lists ${retiredRails.length - retired.length} retired channels that may still hold refundable deposits, and this change would retire ${retired.length} more, past the limit of ${MAX_RETIRED_RAILS}. Close and refund old channels first; a retired channel is never forgotten while it may hold funds. Nothing was written.`,
|
|
21984
|
+
{ retired: retiredRails.length, limit: MAX_RETIRED_RAILS }
|
|
21985
|
+
);
|
|
21986
|
+
}
|
|
21987
|
+
const windows = depositWindows(limits.total, routes);
|
|
21988
|
+
const rules = rails.map((rail) => ruleFor(rail, profile, windows.get(rail.route)));
|
|
21989
|
+
const retiredRules = new Set(
|
|
21990
|
+
retired.map((rail) => rail.policyRuleId).filter((id) => !rules.some((rule) => rule.id === id))
|
|
21991
|
+
);
|
|
21992
|
+
const x402Policy = parseX402Policy({
|
|
21993
|
+
...checks.x402Policy,
|
|
21994
|
+
networks: {
|
|
21995
|
+
...checks.x402Policy.networks,
|
|
21996
|
+
[profile.network]: checks.x402Policy.networks[profile.network] ?? {
|
|
21997
|
+
rpcUrlEnv: checks.rpcUrlEnv
|
|
21998
|
+
}
|
|
21999
|
+
},
|
|
22000
|
+
rules: [
|
|
22001
|
+
...checks.x402Policy.rules.filter((rule) => !rules.some((next) => next.id === rule.id)).map((rule) => retiredRules.has(rule.id) ? { ...rule, enabled: false } : rule),
|
|
22002
|
+
...rules
|
|
22003
|
+
]
|
|
22004
|
+
});
|
|
22005
|
+
await saveX402Policy(x402Policy, getX402PolicyPath());
|
|
22006
|
+
const newRails = rails.filter((rail) => previousRails.get(rail.route)?.salt !== rail.salt);
|
|
22007
|
+
if (newRails.length > 0) {
|
|
22008
|
+
const note = `Approved at the terminal by the device owner during taskmarket agent ${previousPolicy ? "renewal" : "setup"}: rails ${rails.map((rail) => rail.id).join(", ")} on ${profile.network}, deposit ${usd(
|
|
22009
|
+
limits.deposit
|
|
22010
|
+
)} a channel, per request ${usd(limits.perRequest)}, total ${usd(
|
|
22011
|
+
limits.total
|
|
22012
|
+
)} for all channels together, expires ${limits.expiresAt}`;
|
|
22013
|
+
await openBudget(store, newRails[0], note);
|
|
22014
|
+
for (const rail of newRails) {
|
|
22015
|
+
await openSession(store, rail, channelSessionKey(rail, checks.rpcUrl, journalPath));
|
|
22016
|
+
}
|
|
22017
|
+
}
|
|
22018
|
+
const policy = {
|
|
22019
|
+
version: 1,
|
|
22020
|
+
approvedAt: now.toISOString(),
|
|
22021
|
+
models: models.map((model) => model.id),
|
|
22022
|
+
rails,
|
|
22023
|
+
retiredRails,
|
|
22024
|
+
workspace: consentCurrent ? previousPolicy.workspace : { consentVersion: WORKSPACE_CONSENT_VERSION, approvedAt: now.toISOString() }
|
|
22025
|
+
};
|
|
22026
|
+
await saveAgentPolicy(policy);
|
|
22027
|
+
for (const rail of retired) {
|
|
22028
|
+
await store.close(rail.allocationId).catch(() => void 0);
|
|
22029
|
+
}
|
|
22030
|
+
const replaced = retired.filter((rail) => routes.includes(rail.route));
|
|
22031
|
+
const unused = retired.filter((rail) => !routes.includes(rail.route));
|
|
22032
|
+
if (replaced.length > 0) {
|
|
22033
|
+
prompter.say([
|
|
22034
|
+
"",
|
|
22035
|
+
`A new channel replaces ${replaced.map((rail) => rail.id).join(", ")}: a channel's deposit and total are fixed for its life.`,
|
|
22036
|
+
"The replaced channel buys nothing more. Its unused deposit stays in escrow and refundable,",
|
|
22037
|
+
"and it stays listed in the policy so it can be refunded."
|
|
22038
|
+
]);
|
|
22039
|
+
}
|
|
22040
|
+
if (unused.length > 0) {
|
|
22041
|
+
prompter.say([
|
|
22042
|
+
"",
|
|
22043
|
+
`No approved model uses ${unused.map((rail) => `${rail.id} (${rail.route})`).join(", ")} now, so it buys nothing more.`,
|
|
22044
|
+
"Its unused deposit stays in escrow and refundable, and it stays listed in the policy so it",
|
|
22045
|
+
"can be refunded."
|
|
22046
|
+
]);
|
|
22047
|
+
}
|
|
22048
|
+
prompter.say([
|
|
22049
|
+
"",
|
|
22050
|
+
"Spending policy saved. Later launches reuse it until it expires or runs out."
|
|
22051
|
+
]);
|
|
22052
|
+
const compute = await computeStep(
|
|
22053
|
+
deps,
|
|
22054
|
+
prompter,
|
|
22055
|
+
checks.pricing,
|
|
22056
|
+
checks.availableCredits,
|
|
22057
|
+
previousPolicy !== void 0
|
|
22058
|
+
);
|
|
22059
|
+
return { policy, compute };
|
|
22060
|
+
}
|
|
22061
|
+
|
|
22062
|
+
// src/lib/agent/prompter.ts
|
|
22063
|
+
import { createInterface } from "readline";
|
|
22064
|
+
function cancelled() {
|
|
22065
|
+
return new AgentLaunchError(
|
|
22066
|
+
"setup_cancelled",
|
|
22067
|
+
"Setup was cancelled; nothing more was written or bought"
|
|
22068
|
+
);
|
|
21481
22069
|
}
|
|
21482
|
-
function
|
|
21483
|
-
|
|
21484
|
-
|
|
22070
|
+
function terminalPrompter(input = process.stdin, output = process.stderr) {
|
|
22071
|
+
let readline;
|
|
22072
|
+
let closed = false;
|
|
22073
|
+
let reject;
|
|
22074
|
+
const open = () => {
|
|
22075
|
+
if (readline) return readline;
|
|
22076
|
+
readline = createInterface({ input, output, terminal: true });
|
|
22077
|
+
readline.on("SIGINT", () => {
|
|
22078
|
+
output.write("\n");
|
|
22079
|
+
reject?.(cancelled());
|
|
22080
|
+
});
|
|
22081
|
+
readline.on("close", () => {
|
|
22082
|
+
closed = true;
|
|
22083
|
+
reject?.(cancelled());
|
|
22084
|
+
});
|
|
22085
|
+
return readline;
|
|
22086
|
+
};
|
|
22087
|
+
const question = (text) => new Promise((resolve, fail) => {
|
|
22088
|
+
if (closed) {
|
|
22089
|
+
fail(cancelled());
|
|
22090
|
+
return;
|
|
22091
|
+
}
|
|
22092
|
+
reject = fail;
|
|
22093
|
+
open().question(text, (answer) => {
|
|
22094
|
+
reject = void 0;
|
|
22095
|
+
resolve(answer);
|
|
22096
|
+
});
|
|
22097
|
+
});
|
|
22098
|
+
return {
|
|
22099
|
+
say(lines3) {
|
|
22100
|
+
output.write(`${lines3.join("\n")}
|
|
22101
|
+
`);
|
|
22102
|
+
},
|
|
22103
|
+
async ask(text, fallback) {
|
|
22104
|
+
const answer = (await question(`${text} [${fallback}]: `)).trim();
|
|
22105
|
+
return answer === "" ? fallback : answer;
|
|
22106
|
+
},
|
|
22107
|
+
async confirm(text) {
|
|
22108
|
+
const answer = await question(`${text} Type yes to approve: `);
|
|
22109
|
+
return answer.trim().toLowerCase() === "yes";
|
|
22110
|
+
},
|
|
22111
|
+
close() {
|
|
22112
|
+
reject = void 0;
|
|
22113
|
+
readline?.close();
|
|
22114
|
+
readline = void 0;
|
|
22115
|
+
}
|
|
22116
|
+
};
|
|
22117
|
+
}
|
|
22118
|
+
|
|
22119
|
+
// src/lib/agent/setup.ts
|
|
22120
|
+
async function ensureAgentPolicy(options) {
|
|
22121
|
+
const policy = await readAgentPolicy();
|
|
22122
|
+
let assessment;
|
|
22123
|
+
if (policy) {
|
|
22124
|
+
const allocations = createX402Allocations({ journalPath: getX402JournalPath() });
|
|
22125
|
+
assessment = await assessAgentPolicy(policy, {
|
|
22126
|
+
now: options.now,
|
|
22127
|
+
allocation: (id) => allocations.get(id)
|
|
22128
|
+
});
|
|
22129
|
+
if (assessment.reasons.length === 0) return void 0;
|
|
22130
|
+
}
|
|
22131
|
+
if (!options.interactive) {
|
|
22132
|
+
const reasons = assessment ? [...new Set(assessment.reasons.map(({ reason }) => reason))] : ["no_policy"];
|
|
22133
|
+
const window2 = policy && assessment ? await renewalDepositWindow(policy, assessment, options.now ?? /* @__PURE__ */ new Date()) : void 0;
|
|
21485
22134
|
throw new AgentLaunchError(
|
|
21486
|
-
"
|
|
21487
|
-
`
|
|
22135
|
+
"setup_required",
|
|
22136
|
+
policy ? `The agent spending policy at ${getAgentPolicyPath()} needs renewal (${reasons.join(", ")}); run taskmarket agent at a terminal to renew it. Its spending history is kept.${window2 ? ` ${depositWindowMessage(window2, policy)}` : ""}` : `taskmarket agent has no approved spending policy at ${getAgentPolicyPath()}; run taskmarket agent at a terminal to set it up`,
|
|
22137
|
+
{
|
|
22138
|
+
reasons,
|
|
22139
|
+
...window2 ? {
|
|
22140
|
+
depositWindow: {
|
|
22141
|
+
reason: "deposit_window_used",
|
|
22142
|
+
total: policy.rails[0].limits.total,
|
|
22143
|
+
minimumTotal: window2.minimumTotal,
|
|
22144
|
+
...window2.resetsAt ? { resetsAt: window2.resetsAt } : {},
|
|
22145
|
+
rails: window2.blocks
|
|
22146
|
+
}
|
|
22147
|
+
} : {}
|
|
22148
|
+
}
|
|
21488
22149
|
);
|
|
21489
22150
|
}
|
|
21490
|
-
|
|
22151
|
+
const prompter = (options.prompter ?? terminalPrompter)();
|
|
22152
|
+
try {
|
|
22153
|
+
return await (options.onboard ?? runOnboarding)({
|
|
22154
|
+
prompter,
|
|
22155
|
+
walletAddress: options.walletAddress,
|
|
22156
|
+
...policy && assessment ? { renew: { policy, assessment } } : {}
|
|
22157
|
+
});
|
|
22158
|
+
} finally {
|
|
22159
|
+
prompter.close();
|
|
22160
|
+
}
|
|
22161
|
+
}
|
|
22162
|
+
async function renewalDepositWindow(policy, assessment, now) {
|
|
22163
|
+
const limits = policy.rails[0].limits;
|
|
22164
|
+
const reopened = new Set(
|
|
22165
|
+
assessment.reasons.filter(({ reason }) => reason === "allocation_unavailable").map(({ railId }) => railId)
|
|
22166
|
+
);
|
|
22167
|
+
const used = assessment.usage.reduce(
|
|
22168
|
+
(max, usage) => BigInt(usage.used) > max ? BigInt(usage.used) : max,
|
|
22169
|
+
0n
|
|
22170
|
+
);
|
|
22171
|
+
const floors = [
|
|
22172
|
+
BigInt(limits.total),
|
|
22173
|
+
BigInt(limits.deposit) * BigInt(policy.rails.length),
|
|
22174
|
+
used + BigInt(limits.perRequest)
|
|
22175
|
+
];
|
|
22176
|
+
try {
|
|
22177
|
+
return await checkDepositWindows({
|
|
22178
|
+
journalPath: getX402JournalPath(),
|
|
22179
|
+
now,
|
|
22180
|
+
routes: policy.rails.map((rail) => rail.route),
|
|
22181
|
+
rails: policy.rails.map((rail) => ({
|
|
22182
|
+
railId: rail.id,
|
|
22183
|
+
route: rail.route,
|
|
22184
|
+
ruleId: rail.policyRuleId,
|
|
22185
|
+
network: rail.network,
|
|
22186
|
+
asset: rail.asset,
|
|
22187
|
+
newChannel: reopened.has(rail.id)
|
|
22188
|
+
})),
|
|
22189
|
+
limits,
|
|
22190
|
+
floor: floors.reduce((a, b) => a > b ? a : b)
|
|
22191
|
+
});
|
|
22192
|
+
} catch {
|
|
22193
|
+
return void 0;
|
|
22194
|
+
}
|
|
22195
|
+
}
|
|
22196
|
+
function depositWindowMessage(window2, policy) {
|
|
22197
|
+
const usd2 = formatUsdc;
|
|
22198
|
+
const total = policy.rails[0].limits.total;
|
|
22199
|
+
const railIds = window2.blocks.map((block) => block.railId).join(", ");
|
|
22200
|
+
return window2.resetsAt ? `Today's deposit limit is used: renewing with the same total (${usd2(total)}) leaves ${railIds} no room for its first deposit until it resets at ${window2.resetsAt}, and its first turn would be refused (policy_denied). Raise the total to at least ${usd2(window2.minimumTotal)} at renewal, or wait until ${window2.resetsAt}.` : `Today's deposit limit is used: renewing with the same total (${usd2(total)}) leaves ${railIds} no room for its first deposit while a deposit or purchase of unknown outcome counts in full, and its first turn would be refused (policy_denied). Raise the total to at least ${usd2(window2.minimumTotal)} at renewal, or reconcile the unknown outcome first.`;
|
|
21491
22201
|
}
|
|
21492
22202
|
|
|
21493
22203
|
// src/lib/agent/signals.ts
|
|
@@ -21544,10 +22254,10 @@ var STOP_TIMEOUT_MS = 15e3;
|
|
|
21544
22254
|
var log = (message) => process.stderr.write(`[taskmarket] ${message}
|
|
21545
22255
|
`);
|
|
21546
22256
|
function sessionLog() {
|
|
21547
|
-
const file =
|
|
22257
|
+
const file = path5.join(getTaskmarketHome(), "agent", "session.log");
|
|
21548
22258
|
return (message) => {
|
|
21549
22259
|
try {
|
|
21550
|
-
mkdirSync(
|
|
22260
|
+
mkdirSync(path5.dirname(file), { recursive: true, mode: 448 });
|
|
21551
22261
|
appendFileSync(file, `${(/* @__PURE__ */ new Date()).toISOString()} ${message}
|
|
21552
22262
|
`, { mode: 384 });
|
|
21553
22263
|
} catch {
|
|
@@ -21564,7 +22274,16 @@ function withTimeout(promise, ms) {
|
|
|
21564
22274
|
]).finally(() => clearTimeout(timer));
|
|
21565
22275
|
}
|
|
21566
22276
|
async function runAgent(options) {
|
|
21567
|
-
|
|
22277
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
22278
|
+
if (!await keystoreExists()) {
|
|
22279
|
+
throw new AgentLaunchError(
|
|
22280
|
+
"wallet_required",
|
|
22281
|
+
"No wallet is set up. Import one with `taskmarket wallet import` (or create one with `taskmarket init`), then run taskmarket agent again; this command never asks for a key"
|
|
22282
|
+
);
|
|
22283
|
+
}
|
|
22284
|
+
const keystore = await loadKeystore();
|
|
22285
|
+
await ensureAgentPolicy({ interactive, walletAddress: keystore.walletAddress });
|
|
22286
|
+
if (!interactive) {
|
|
21568
22287
|
throw new AgentLaunchError(
|
|
21569
22288
|
"interactive_terminal_required",
|
|
21570
22289
|
"taskmarket agent opens an interactive session and needs a terminal"
|
|
@@ -21574,7 +22293,7 @@ async function runAgent(options) {
|
|
|
21574
22293
|
onCleanupSignal: () => log("Finishing: settling purchases and stopping the sandbox")
|
|
21575
22294
|
});
|
|
21576
22295
|
try {
|
|
21577
|
-
return await runSession(options, signals);
|
|
22296
|
+
return await runSession(options, signals, keystore);
|
|
21578
22297
|
} finally {
|
|
21579
22298
|
signals.dispose();
|
|
21580
22299
|
}
|
|
@@ -21585,37 +22304,25 @@ function interruptedLaunch() {
|
|
|
21585
22304
|
"The launch was interrupted before Pi started"
|
|
21586
22305
|
);
|
|
21587
22306
|
}
|
|
21588
|
-
async function runSession(options, signals) {
|
|
22307
|
+
async function runSession(options, signals, keystore) {
|
|
21589
22308
|
const checkInterrupted = () => {
|
|
21590
22309
|
if (signals.interrupted) throw interruptedLaunch();
|
|
21591
22310
|
};
|
|
21592
|
-
|
|
21593
|
-
|
|
21594
|
-
|
|
21595
|
-
|
|
21596
|
-
);
|
|
21597
|
-
}
|
|
21598
|
-
const keystore = await loadKeystore();
|
|
21599
|
-
const policy = await loadAgentPolicy();
|
|
21600
|
-
const models = selectModels(policy, options.model);
|
|
21601
|
-
let account;
|
|
21602
|
-
const getAccount = () => {
|
|
21603
|
-
account ??= createWalletAccountFromKeystore(keystore).catch((error) => {
|
|
21604
|
-
account = void 0;
|
|
21605
|
-
throw error;
|
|
21606
|
-
});
|
|
21607
|
-
return account;
|
|
21608
|
-
};
|
|
21609
|
-
const rails = await createAgentRails({
|
|
21610
|
-
policy,
|
|
21611
|
-
models,
|
|
21612
|
-
walletAddress: keystore.walletAddress,
|
|
21613
|
-
getAccount
|
|
22311
|
+
let models = [];
|
|
22312
|
+
const { rails } = await openAgentChannels({
|
|
22313
|
+
keystore,
|
|
22314
|
+
models: (policy) => models = selectModels(policy, options.model)
|
|
21614
22315
|
});
|
|
21615
22316
|
checkInterrupted();
|
|
21616
22317
|
await reconcileLeftoverOperations(rails, log);
|
|
21617
22318
|
checkInterrupted();
|
|
21618
|
-
const
|
|
22319
|
+
const observeCompute = computeCreditObserver(sessionLog());
|
|
22320
|
+
const budget = createSessionBudget({
|
|
22321
|
+
rails,
|
|
22322
|
+
transport: createAgentTransport(rails),
|
|
22323
|
+
observeCompute
|
|
22324
|
+
});
|
|
22325
|
+
const transport = budget.transport;
|
|
21619
22326
|
let offered;
|
|
21620
22327
|
try {
|
|
21621
22328
|
offered = (await transport.models(AbortSignal.any([AbortSignal.timeout(3e4), signals.setupSignal]))).map((row) => row.id);
|
|
@@ -21633,15 +22340,15 @@ async function runSession(options, signals) {
|
|
|
21633
22340
|
`None of the approved models (${models.join(", ")}) is qualified by xgate on a route the policy pays for`
|
|
21634
22341
|
);
|
|
21635
22342
|
}
|
|
21636
|
-
const observeCompute = computeCreditObserver(sessionLog());
|
|
21637
22343
|
const observations = /* @__PURE__ */ new Set();
|
|
21638
22344
|
const createBroker = () => new BrokerConnector({
|
|
21639
22345
|
apiUrl: apiUrl(),
|
|
21640
22346
|
deviceId: keystore.deviceId,
|
|
21641
22347
|
apiToken: keystore.apiToken,
|
|
21642
22348
|
purpose: "interactive",
|
|
21643
|
-
idempotencyKey:
|
|
22349
|
+
idempotencyKey: randomUUID3(),
|
|
21644
22350
|
onCreditWarning: (warning) => {
|
|
22351
|
+
budget.noteCreditWarning(warning);
|
|
21645
22352
|
if (warning !== "low_credit" && warning !== "credit_exhausted") return;
|
|
21646
22353
|
const observed = observeCompute({ creditWarning: warning });
|
|
21647
22354
|
observations.add(observed);
|
|
@@ -21681,7 +22388,7 @@ async function runSession(options, signals) {
|
|
|
21681
22388
|
return await runPiSession(launch, {
|
|
21682
22389
|
secrets: [broker.toolKey.privateKey, keystore.apiToken, keystore.encryptedKey],
|
|
21683
22390
|
broker,
|
|
21684
|
-
|
|
22391
|
+
budget,
|
|
21685
22392
|
signals
|
|
21686
22393
|
});
|
|
21687
22394
|
} finally {
|
|
@@ -21693,7 +22400,7 @@ async function runSession(options, signals) {
|
|
|
21693
22400
|
STOP_TIMEOUT_MS
|
|
21694
22401
|
);
|
|
21695
22402
|
}
|
|
21696
|
-
await withTimeout(Promise.allSettled([...observations]), STOP_TIMEOUT_MS);
|
|
22403
|
+
await withTimeout(Promise.allSettled([...observations, budget.settled()]), STOP_TIMEOUT_MS);
|
|
21697
22404
|
}
|
|
21698
22405
|
}
|
|
21699
22406
|
async function runPiSession(launch, context) {
|
|
@@ -21720,8 +22427,15 @@ async function runPiSession(launch, context) {
|
|
|
21720
22427
|
const inferenceFds = launch.inferenceFds;
|
|
21721
22428
|
const inference = serveInferenceChannel(
|
|
21722
22429
|
{ requests: stdio[inferenceFds.request], replies: stdio[inferenceFds.reply] },
|
|
21723
|
-
context.transport,
|
|
21724
|
-
{
|
|
22430
|
+
context.budget.transport,
|
|
22431
|
+
{
|
|
22432
|
+
log: diagnostics,
|
|
22433
|
+
views: {
|
|
22434
|
+
budget: (view) => context.budget.view(view),
|
|
22435
|
+
creditOffer: () => context.budget.creditOffer(),
|
|
22436
|
+
buyCredits: (amountUsd) => context.budget.buyCredits(amountUsd)
|
|
22437
|
+
}
|
|
22438
|
+
}
|
|
21725
22439
|
);
|
|
21726
22440
|
let killTimer;
|
|
21727
22441
|
context.signals.piStarted(() => {
|