@t2000/sdk 5.15.1 → 5.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +140 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -4
- package/dist/index.d.ts +58 -4
- package/dist/index.js +140 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1226,10 +1226,10 @@ async function finalize(response, opts) {
|
|
|
1226
1226
|
return { status: response.status, body: body2, paid: opts.paid };
|
|
1227
1227
|
}
|
|
1228
1228
|
async function makeGrpcBuildClient(client) {
|
|
1229
|
-
const { SuiGrpcClient:
|
|
1229
|
+
const { SuiGrpcClient: SuiGrpcClient3 } = await import('@mysten/sui/grpc');
|
|
1230
1230
|
const network = client.network === "testnet" ? "testnet" : "mainnet";
|
|
1231
1231
|
const baseUrl = network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
|
|
1232
|
-
return new
|
|
1232
|
+
return new SuiGrpcClient3({ baseUrl, network });
|
|
1233
1233
|
}
|
|
1234
1234
|
function atomicToHuman(raw, decimals) {
|
|
1235
1235
|
return Number(raw) / 10 ** decimals;
|
|
@@ -1934,7 +1934,9 @@ function body(params, stream) {
|
|
|
1934
1934
|
return JSON.stringify({
|
|
1935
1935
|
model: params.model,
|
|
1936
1936
|
messages: params.messages,
|
|
1937
|
-
|
|
1937
|
+
// include_usage → the final stream chunk carries usage + x_receipt_id
|
|
1938
|
+
// (the confidential attestation receipt) so we can surface it after a stream.
|
|
1939
|
+
...stream ? { stream: true, stream_options: { include_usage: true } } : {},
|
|
1938
1940
|
...params.maxTokens != null ? { max_tokens: params.maxTokens } : {},
|
|
1939
1941
|
...params.temperature != null ? { temperature: params.temperature } : {}
|
|
1940
1942
|
});
|
|
@@ -1950,12 +1952,14 @@ async function chatCompletion(params) {
|
|
|
1950
1952
|
if (!res.ok) {
|
|
1951
1953
|
await failBody(res);
|
|
1952
1954
|
}
|
|
1955
|
+
const receiptId = res.headers.get("x-receipt-id") ?? void 0;
|
|
1953
1956
|
const raw = await res.json();
|
|
1954
1957
|
const content = raw?.choices?.[0]?.message?.content ?? "";
|
|
1955
1958
|
return {
|
|
1956
1959
|
content,
|
|
1957
1960
|
model: raw?.model ?? params.model,
|
|
1958
1961
|
usage: usageOf(raw),
|
|
1962
|
+
receiptId,
|
|
1959
1963
|
raw
|
|
1960
1964
|
};
|
|
1961
1965
|
}
|
|
@@ -1969,11 +1973,12 @@ async function* chatCompletionStream(params) {
|
|
|
1969
1973
|
});
|
|
1970
1974
|
if (!(res.ok && res.body)) {
|
|
1971
1975
|
await failBody(res);
|
|
1972
|
-
return;
|
|
1976
|
+
return {};
|
|
1973
1977
|
}
|
|
1974
1978
|
const reader = res.body.getReader();
|
|
1975
1979
|
const decoder = new TextDecoder();
|
|
1976
1980
|
let buffer = "";
|
|
1981
|
+
let receiptId;
|
|
1977
1982
|
while (true) {
|
|
1978
1983
|
const { done, value } = await reader.read();
|
|
1979
1984
|
if (done) {
|
|
@@ -1989,10 +1994,13 @@ async function* chatCompletionStream(params) {
|
|
|
1989
1994
|
}
|
|
1990
1995
|
const data = trimmed.slice(5).trim();
|
|
1991
1996
|
if (data === "[DONE]") {
|
|
1992
|
-
return;
|
|
1997
|
+
return { receiptId };
|
|
1993
1998
|
}
|
|
1994
1999
|
try {
|
|
1995
2000
|
const json = JSON.parse(data);
|
|
2001
|
+
if (json.x_receipt_id) {
|
|
2002
|
+
receiptId = json.x_receipt_id;
|
|
2003
|
+
}
|
|
1996
2004
|
const delta = json.choices?.[0]?.delta?.content;
|
|
1997
2005
|
if (typeof delta === "string" && delta) {
|
|
1998
2006
|
yield delta;
|
|
@@ -2001,6 +2009,7 @@ async function* chatCompletionStream(params) {
|
|
|
2001
2009
|
}
|
|
2002
2010
|
}
|
|
2003
2011
|
}
|
|
2012
|
+
return { receiptId };
|
|
2004
2013
|
}
|
|
2005
2014
|
async function listModels(opts) {
|
|
2006
2015
|
const base = opts?.apiBase ?? DEFAULT_API_BASE;
|
|
@@ -2021,6 +2030,124 @@ async function listModels(opts) {
|
|
|
2021
2030
|
privacy: m.privacy ?? m.privacy_tier
|
|
2022
2031
|
}));
|
|
2023
2032
|
}
|
|
2033
|
+
var RECEIPT_ANCHORED_SUFFIX = "::anchor::ReceiptAnchored";
|
|
2034
|
+
function fullnodeUrl(network) {
|
|
2035
|
+
return network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
|
|
2036
|
+
}
|
|
2037
|
+
async function verifyReceipt(receiptId, opts = {}) {
|
|
2038
|
+
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
2039
|
+
const network = opts.network ?? "mainnet";
|
|
2040
|
+
const checks = [];
|
|
2041
|
+
let receipt = null;
|
|
2042
|
+
try {
|
|
2043
|
+
const res = await fetch(`${base}/aci/receipts/${encodeURIComponent(receiptId)}`);
|
|
2044
|
+
if (res.ok) {
|
|
2045
|
+
receipt = await res.json();
|
|
2046
|
+
}
|
|
2047
|
+
} catch {
|
|
2048
|
+
}
|
|
2049
|
+
if (!receipt?.event_log) {
|
|
2050
|
+
checks.push({
|
|
2051
|
+
name: "Receipt",
|
|
2052
|
+
status: "fail",
|
|
2053
|
+
detail: "receipt not found or malformed",
|
|
2054
|
+
trust: "receipt-asserted"
|
|
2055
|
+
});
|
|
2056
|
+
return { receiptId, verified: false, anchorVerified: false, checks };
|
|
2057
|
+
}
|
|
2058
|
+
const wireHash = receipt.event_log.find((e) => e.type === "response.returned")?.wire_hash;
|
|
2059
|
+
const workloadId = receipt.workload_id;
|
|
2060
|
+
checks.push({
|
|
2061
|
+
name: "Receipt",
|
|
2062
|
+
status: wireHash && workloadId ? "pass" : "fail",
|
|
2063
|
+
detail: wireHash ? `well-formed (${receipt.event_log.length} log entries, workload ${workloadId})` : "missing response wire_hash / workload_id",
|
|
2064
|
+
trust: "receipt-asserted"
|
|
2065
|
+
});
|
|
2066
|
+
const upstreamEv = receipt.event_log.find((e) => e.type === "upstream.verified");
|
|
2067
|
+
const upstreamOk = upstreamEv?.result === "verified";
|
|
2068
|
+
checks.push({
|
|
2069
|
+
name: "Confidential upstream",
|
|
2070
|
+
status: upstreamEv ? upstreamOk ? "pass" : "fail" : "skip",
|
|
2071
|
+
detail: upstreamEv ? `${upstreamEv.provider ?? upstreamEv.upstream_name ?? "upstream"}: ${upstreamEv.result ?? "unknown"}${upstreamEv.tcb_status ? ` (TCB ${upstreamEv.tcb_status})` : ""}` : "no upstream.verified event (routed/non-confidential?)",
|
|
2072
|
+
trust: "receipt-asserted"
|
|
2073
|
+
});
|
|
2074
|
+
let anchorVerified = false;
|
|
2075
|
+
let anchor;
|
|
2076
|
+
let digest;
|
|
2077
|
+
try {
|
|
2078
|
+
const res = await fetch(`${base}/aci/anchor/${encodeURIComponent(receiptId)}`);
|
|
2079
|
+
if (res.ok) {
|
|
2080
|
+
const j = await res.json();
|
|
2081
|
+
digest = j.txDigest;
|
|
2082
|
+
}
|
|
2083
|
+
} catch {
|
|
2084
|
+
}
|
|
2085
|
+
if (!digest) {
|
|
2086
|
+
checks.push({
|
|
2087
|
+
name: "Sui anchor",
|
|
2088
|
+
status: "fail",
|
|
2089
|
+
detail: `no anchor on record \u2014 POST ${base}/aci/anchor/${receiptId} to create one`,
|
|
2090
|
+
trust: "trustless"
|
|
2091
|
+
});
|
|
2092
|
+
} else {
|
|
2093
|
+
try {
|
|
2094
|
+
const client = new grpc.SuiGrpcClient({ baseUrl: fullnodeUrl(network), network });
|
|
2095
|
+
const tx = await client.core.getTransaction({
|
|
2096
|
+
digest,
|
|
2097
|
+
include: { events: true }
|
|
2098
|
+
});
|
|
2099
|
+
const txn = tx.$kind === "Transaction" ? tx.Transaction : tx.FailedTransaction;
|
|
2100
|
+
const ev = (txn.events ?? []).find(
|
|
2101
|
+
(e) => e.eventType.endsWith(RECEIPT_ANCHORED_SUFFIX)
|
|
2102
|
+
);
|
|
2103
|
+
const data = ev?.json ?? {};
|
|
2104
|
+
const onChainReceipt = String(data.receipt_id ?? "");
|
|
2105
|
+
const onChainWire = String(data.wire_hash ?? "");
|
|
2106
|
+
const onChainWorkload = String(data.workload_id ?? "");
|
|
2107
|
+
const matches = onChainReceipt === receiptId && onChainWire === wireHash && onChainWorkload === workloadId;
|
|
2108
|
+
anchorVerified = matches;
|
|
2109
|
+
anchor = {
|
|
2110
|
+
txDigest: digest,
|
|
2111
|
+
anchoredAtMs: data.anchored_at_ms ? String(data.anchored_at_ms) : void 0,
|
|
2112
|
+
anchoredBy: data.anchored_by ? String(data.anchored_by) : void 0,
|
|
2113
|
+
explorer: `https://suiscan.xyz/${network}/tx/${digest}`
|
|
2114
|
+
};
|
|
2115
|
+
checks.push({
|
|
2116
|
+
name: "Sui anchor",
|
|
2117
|
+
status: matches ? "pass" : "fail",
|
|
2118
|
+
detail: matches ? `on-chain ReceiptAnchored matches (wire_hash + workload_id), tx ${digest}` : `on-chain event does NOT match the receipt (wire ${onChainWire || "absent"})`,
|
|
2119
|
+
trust: "trustless"
|
|
2120
|
+
});
|
|
2121
|
+
} catch (e) {
|
|
2122
|
+
checks.push({
|
|
2123
|
+
name: "Sui anchor",
|
|
2124
|
+
status: "fail",
|
|
2125
|
+
detail: `could not read anchor tx ${digest}: ${e instanceof Error ? e.message : "error"}`,
|
|
2126
|
+
trust: "trustless"
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
checks.push({
|
|
2131
|
+
name: "Receipt signature",
|
|
2132
|
+
status: "skip",
|
|
2133
|
+
detail: receipt.signature ? "present (local recompute via RedPill keyset canonicalization = roadmap)" : "no signature on receipt",
|
|
2134
|
+
trust: "roadmap"
|
|
2135
|
+
});
|
|
2136
|
+
return {
|
|
2137
|
+
receiptId,
|
|
2138
|
+
verified: Boolean(wireHash && workloadId) && anchorVerified,
|
|
2139
|
+
anchorVerified,
|
|
2140
|
+
checks,
|
|
2141
|
+
wireHash,
|
|
2142
|
+
workloadId,
|
|
2143
|
+
upstream: upstreamEv ? {
|
|
2144
|
+
provider: upstreamEv.provider ?? upstreamEv.upstream_name,
|
|
2145
|
+
result: upstreamEv.result,
|
|
2146
|
+
tcbStatus: upstreamEv.tcb_status
|
|
2147
|
+
} : void 0,
|
|
2148
|
+
anchor
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2024
2151
|
var DEFAULT_CONFIG_DIR = path.join(os.homedir(), ".t2000");
|
|
2025
2152
|
function resolveConfigPath(configDir) {
|
|
2026
2153
|
return path.join(configDir ?? DEFAULT_CONFIG_DIR, "config.json");
|
|
@@ -2297,7 +2424,8 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2297
2424
|
async chat(params) {
|
|
2298
2425
|
return chatCompletion(params);
|
|
2299
2426
|
}
|
|
2300
|
-
/** Streaming chat completion — async-iterate the assistant text deltas
|
|
2427
|
+
/** Streaming chat completion — async-iterate the assistant text deltas;
|
|
2428
|
+
* the generator returns `{ receiptId }` (confidential attestation) at the end. */
|
|
2301
2429
|
chatStream(params) {
|
|
2302
2430
|
return chatCompletionStream(params);
|
|
2303
2431
|
}
|
|
@@ -2305,6 +2433,11 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2305
2433
|
async models(opts) {
|
|
2306
2434
|
return listModels(opts);
|
|
2307
2435
|
}
|
|
2436
|
+
/** Verify a confidential response by receipt id — checks the signed receipt
|
|
2437
|
+
* + its trustless on-chain Sui anchor. Fails closed on any mismatch. */
|
|
2438
|
+
async verify(receiptId, opts) {
|
|
2439
|
+
return verifyReceipt(receiptId, opts);
|
|
2440
|
+
}
|
|
2308
2441
|
// -- Swap --
|
|
2309
2442
|
async swap(params) {
|
|
2310
2443
|
this.limits.assert({
|
|
@@ -3192,6 +3325,7 @@ exports.usdcToRaw = usdcToRaw;
|
|
|
3192
3325
|
exports.validateAddress = validateAddress;
|
|
3193
3326
|
exports.validateLabel = validateLabel;
|
|
3194
3327
|
exports.verifyCetusRouteCoinMatch = verifyCetusRouteCoinMatch;
|
|
3328
|
+
exports.verifyReceipt = verifyReceipt;
|
|
3195
3329
|
exports.walletExists = walletExists;
|
|
3196
3330
|
exports.writeLimitsFile = writeLimitsFile;
|
|
3197
3331
|
//# sourceMappingURL=index.cjs.map
|