stellarium-ts 0.15.0 → 0.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/client/operatorAuth.d.ts +19 -0
- package/dist/client/operatorAuth.d.ts.map +1 -0
- package/dist/client/operatorAuth.js +21 -0
- package/dist/client/operatorClient.d.ts +75 -16
- package/dist/client/operatorClient.d.ts.map +1 -1
- package/dist/client/operatorClient.js +82 -23
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +11 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/resource/inference.d.ts +38 -0
- package/dist/resource/inference.d.ts.map +1 -0
- package/dist/resource/inference.js +74 -0
- package/dist/resource/invoker.d.ts +65 -8
- package/dist/resource/invoker.d.ts.map +1 -1
- package/dist/resource/invoker.js +120 -21
- package/dist/resource/repository.d.ts +29 -5
- package/dist/resource/repository.d.ts.map +1 -1
- package/dist/resource/repository.js +38 -7
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +206 -52
- package/dist/server.d.ts +13 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +26 -4
- package/dist/service.d.ts +8 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +3 -3
- package/dist/tests/client/operatorClient.test.js +94 -36
- package/dist/tests/db/db.test.js +18 -1
- package/dist/tests/helpers.d.ts +11 -1
- package/dist/tests/helpers.d.ts.map +1 -1
- package/dist/tests/helpers.js +38 -3
- package/dist/tests/integration/network.test.js +78 -7
- package/dist/tests/resource/invoker.test.js +95 -4
- package/dist/tests/resource/repository.test.js +20 -6
- package/dist/tests/routes.test.js +194 -23
- package/dist/tests/server.test.js +35 -8
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The scheme of the `Authorization` header on node requests to the operator. */
|
|
2
|
+
export declare const OPERATOR_AUTH_SCHEME = "Stellarium";
|
|
3
|
+
/**
|
|
4
|
+
* The object a node signs to authenticate one operator request. `path` is the URL path without the
|
|
5
|
+
* query string, and `bodyHash` is `hashData` of the parsed JSON body (`{}` when there is none).
|
|
6
|
+
* Key order is part of the signed bytes. The operator rebuilds this in apps/operator/src/auth/nodeAuth.ts.
|
|
7
|
+
*/
|
|
8
|
+
export declare function operatorRequestPayload(method: string, path: string, body: unknown, timestamp: string): {
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
bodyHash: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* `Authorization` header value for a request to `url`: the scheme, then base64url JSON of
|
|
16
|
+
* `{ publicKey, timestamp, signature }`. The operator accepts timestamps within a few minutes of its clock.
|
|
17
|
+
*/
|
|
18
|
+
export declare function operatorAuthorization(method: string, url: string, body: unknown, publicKey: string, privateKey: string): string;
|
|
19
|
+
//# sourceMappingURL=operatorAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operatorAuth.d.ts","sourceRoot":"","sources":["../../src/client/operatorAuth.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM;;;;;EAEpG;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK/H"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { hashData, signData } from "../crypto/utils.js";
|
|
2
|
+
/** The scheme of the `Authorization` header on node requests to the operator. */
|
|
3
|
+
export const OPERATOR_AUTH_SCHEME = 'Stellarium';
|
|
4
|
+
/**
|
|
5
|
+
* The object a node signs to authenticate one operator request. `path` is the URL path without the
|
|
6
|
+
* query string, and `bodyHash` is `hashData` of the parsed JSON body (`{}` when there is none).
|
|
7
|
+
* Key order is part of the signed bytes. The operator rebuilds this in apps/operator/src/auth/nodeAuth.ts.
|
|
8
|
+
*/
|
|
9
|
+
export function operatorRequestPayload(method, path, body, timestamp) {
|
|
10
|
+
return { method: method.toUpperCase(), path, bodyHash: hashData(body ?? {}), timestamp };
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* `Authorization` header value for a request to `url`: the scheme, then base64url JSON of
|
|
14
|
+
* `{ publicKey, timestamp, signature }`. The operator accepts timestamps within a few minutes of its clock.
|
|
15
|
+
*/
|
|
16
|
+
export function operatorAuthorization(method, url, body, publicKey, privateKey) {
|
|
17
|
+
const timestamp = new Date().toISOString();
|
|
18
|
+
const signature = signData(operatorRequestPayload(method, new URL(url).pathname, body, timestamp), privateKey);
|
|
19
|
+
const credentials = Buffer.from(JSON.stringify({ publicKey, timestamp, signature })).toString('base64url');
|
|
20
|
+
return `${OPERATOR_AUTH_SCHEME} ${credentials}`;
|
|
21
|
+
}
|
|
@@ -1,26 +1,85 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
export type PaymentSubmission = FixedPaymentSubmission | InferencePaymentSubmission;
|
|
2
|
+
export interface FixedPaymentVoucher {
|
|
3
|
+
kind?: undefined;
|
|
4
|
+
requestId: string;
|
|
5
|
+
invocationId: string;
|
|
6
|
+
amount: number;
|
|
7
|
+
recipientOrganizationId: string;
|
|
8
|
+
signature: string;
|
|
9
|
+
expiresAt: string;
|
|
10
|
+
invocationHash: string;
|
|
11
|
+
publicKey: string;
|
|
12
|
+
}
|
|
13
|
+
export interface InferenceVoucher {
|
|
14
|
+
kind: 'inference';
|
|
15
|
+
requestId: string;
|
|
16
|
+
invocationId: string;
|
|
17
|
+
maxAmount: number;
|
|
18
|
+
inputCostMicroUsdPerMillionTokens: number;
|
|
19
|
+
outputCostMicroUsdPerMillionTokens: number;
|
|
20
|
+
maxTokens: number;
|
|
21
|
+
recipientOrganizationId: string;
|
|
22
|
+
signature: string;
|
|
23
|
+
expiresAt: string;
|
|
24
|
+
invocationHash: string;
|
|
25
|
+
publicKey: string;
|
|
26
|
+
}
|
|
27
|
+
export interface FixedPaymentSubmission {
|
|
28
|
+
voucher: FixedPaymentVoucher;
|
|
29
|
+
}
|
|
30
|
+
/** The provider reports the call's usage; the operator charges it at the voucher's rates, up to the held `maxAmount`. */
|
|
31
|
+
export interface InferencePaymentSubmission {
|
|
32
|
+
voucher: InferenceVoucher;
|
|
33
|
+
usage: {
|
|
34
|
+
inputTokens: number;
|
|
35
|
+
outputTokens: number;
|
|
11
36
|
};
|
|
12
37
|
}
|
|
13
|
-
|
|
14
|
-
export
|
|
38
|
+
/** Whether the operator placed a hold for a voucher. A refusal carries the operator's status and error. */
|
|
39
|
+
export type AuthorizeResult = {
|
|
40
|
+
ok: true;
|
|
41
|
+
} | {
|
|
42
|
+
ok: false;
|
|
43
|
+
status: number;
|
|
44
|
+
error: string;
|
|
45
|
+
};
|
|
46
|
+
export declare const OPERATOR_MAX_RETRIES = 5;
|
|
47
|
+
/** Authorization runs while the caller waits, so it gives up much sooner than capture and release. */
|
|
48
|
+
export declare const AUTHORIZE_MAX_RETRIES = 2;
|
|
49
|
+
export declare const OPERATOR_BASE_DELAY_MS = 1000;
|
|
50
|
+
export declare const AUTHORIZE_BASE_DELAY_MS = 200;
|
|
15
51
|
/** Per attempt. A timed-out attempt is retried like a network error. */
|
|
16
|
-
export declare const
|
|
52
|
+
export declare const OPERATOR_TIMEOUT_MS = 10000;
|
|
53
|
+
/** Talks to the operator as this node. Every request is signed with the node's key. */
|
|
17
54
|
export declare class OperatorClient {
|
|
18
55
|
private readonly url;
|
|
19
|
-
|
|
56
|
+
private readonly publicKey;
|
|
57
|
+
private readonly privateKey;
|
|
58
|
+
constructor(url: string | undefined, publicKey: string, privateKey: string);
|
|
20
59
|
/**
|
|
21
|
-
*
|
|
60
|
+
* POSTs `body`, retrying `RETRYABLE_STATUSES` and network errors up to `retries` times.
|
|
61
|
+
* Each attempt is signed afresh, since the operator only accepts recent timestamps.
|
|
22
62
|
* Throws the last network error if the operator could not be reached, or if no operator URL is configured.
|
|
23
63
|
*/
|
|
24
|
-
|
|
64
|
+
private post;
|
|
65
|
+
/**
|
|
66
|
+
* Returns the organization this node is enrolled in. With an `enrollmentToken` from the dashboard,
|
|
67
|
+
* enrolls the node first; a node that is already enrolled ignores the token. Throws if the node is
|
|
68
|
+
* not enrolled or the operator refuses.
|
|
69
|
+
*/
|
|
70
|
+
session(enrollmentToken?: string): Promise<{
|
|
71
|
+
organizationId: string;
|
|
72
|
+
}>;
|
|
73
|
+
/**
|
|
74
|
+
* Asks the operator to hold the voucher's amount (or `maxAmount`) on the payer's balance, before
|
|
75
|
+
* running the paid function. An unreachable operator is reported as a 503 refusal.
|
|
76
|
+
*/
|
|
77
|
+
authorize(voucher: FixedPaymentVoucher | InferenceVoucher): Promise<AuthorizeResult>;
|
|
78
|
+
/** Charges a held voucher: its amount, or for inference the reported usage capped at the hold. */
|
|
79
|
+
capture(payment: PaymentSubmission): Promise<void>;
|
|
80
|
+
/** Releases a held voucher without charging it, for a call that failed or cost nothing. */
|
|
81
|
+
release(voucher: FixedPaymentVoucher | InferenceVoucher): Promise<void>;
|
|
82
|
+
/** Logs a refusal instead of throwing: nothing waits on capture or release. Throws only if the operator can't be reached. */
|
|
83
|
+
private settle;
|
|
25
84
|
}
|
|
26
85
|
//# sourceMappingURL=operatorClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operatorClient.d.ts","sourceRoot":"","sources":["../../src/client/operatorClient.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"operatorClient.d.ts","sourceRoot":"","sources":["../../src/client/operatorClient.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,GAAG,0BAA0B,CAAC;AAEpF,MAAM,WAAW,mBAAmB;IAChC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB,EAAE,MAAM,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC,EAAE,MAAM,CAAC;IAC1C,kCAAkC,EAAE,MAAM,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,EAAE,MAAM,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACnC,OAAO,EAAE,mBAAmB,CAAC;CAChC;AAED,yHAAyH;AACzH,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,KAAK,EAAE;QACH,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC;CACL;AAED,2GAA2G;AAC3G,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1F,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,sGAAsG;AACtG,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAwB1C,uFAAuF;AACvF,qBAAa,cAAc;IACX,OAAO,CAAC,QAAQ,CAAC,GAAG;IAAsB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAAU,OAAO,CAAC,QAAQ,CAAC,UAAU;IAArH,YAA6B,GAAG,EAAE,MAAM,GAAG,SAAS,EAAmB,SAAS,EAAE,MAAM,EAAmB,UAAU,EAAE,MAAM,EAAI;IAEjI;;;;OAIG;YACW,IAAI;IA+BlB;;;;OAIG;IACG,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,CAM3E;IAED;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAczF;IAED,kGAAkG;IAC5F,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvD;IAED,2FAA2F;IACrF,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;IAED,6HAA6H;YAC/G,MAAM;CAMvB"}
|
|
@@ -1,62 +1,121 @@
|
|
|
1
|
-
|
|
2
|
-
export const
|
|
1
|
+
import { operatorAuthorization } from "./operatorAuth.js";
|
|
2
|
+
export const OPERATOR_MAX_RETRIES = 5;
|
|
3
|
+
/** Authorization runs while the caller waits, so it gives up much sooner than capture and release. */
|
|
4
|
+
export const AUTHORIZE_MAX_RETRIES = 2;
|
|
5
|
+
export const OPERATOR_BASE_DELAY_MS = 1000;
|
|
6
|
+
export const AUTHORIZE_BASE_DELAY_MS = 200;
|
|
3
7
|
/** Per attempt. A timed-out attempt is retried like a network error. */
|
|
4
|
-
export const
|
|
8
|
+
export const OPERATOR_TIMEOUT_MS = 10_000;
|
|
5
9
|
/**
|
|
6
|
-
* Transient failures. Resending is safe even if an earlier attempt reached the operator:
|
|
7
|
-
*
|
|
8
|
-
* Rejections (400, 401, 404, 409, 422) are not retried because they won't change.
|
|
10
|
+
* Transient failures. Resending is safe even if an earlier attempt reached the operator: every payment
|
|
11
|
+
* request is idempotent per voucher (requestId, invocationId).
|
|
12
|
+
* Rejections (400, 401, 402, 403, 404, 409, 422) are not retried because they won't change.
|
|
9
13
|
*/
|
|
10
14
|
const RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);
|
|
11
15
|
/**
|
|
12
|
-
* Delay before retry `attempt` (0-based): exponential backoff
|
|
16
|
+
* Delay before retry `attempt` (0-based): exponential backoff from `baseDelayMs`,
|
|
13
17
|
* or the operator's `Retry-After` seconds when that is longer.
|
|
14
18
|
*/
|
|
15
|
-
function retryDelayMs(response, attempt) {
|
|
16
|
-
const backoff =
|
|
19
|
+
function retryDelayMs(response, attempt, baseDelayMs) {
|
|
20
|
+
const backoff = baseDelayMs * 2 ** attempt;
|
|
17
21
|
const retryAfterSeconds = Number(response?.headers.get('retry-after') ?? NaN);
|
|
18
22
|
return Number.isFinite(retryAfterSeconds) ? Math.max(backoff, retryAfterSeconds * 1000) : backoff;
|
|
19
23
|
}
|
|
24
|
+
async function errorMessage(response) {
|
|
25
|
+
const body = await response.json().catch(() => undefined);
|
|
26
|
+
return typeof body?.error === 'string' ? body.error : `${response.status} ${response.statusText}`.trim();
|
|
27
|
+
}
|
|
28
|
+
/** Talks to the operator as this node. Every request is signed with the node's key. */
|
|
20
29
|
export class OperatorClient {
|
|
21
30
|
url;
|
|
22
|
-
|
|
31
|
+
publicKey;
|
|
32
|
+
privateKey;
|
|
33
|
+
constructor(url, publicKey, privateKey) {
|
|
23
34
|
this.url = url;
|
|
35
|
+
this.publicKey = publicKey;
|
|
36
|
+
this.privateKey = privateKey;
|
|
24
37
|
}
|
|
25
38
|
/**
|
|
26
|
-
*
|
|
39
|
+
* POSTs `body`, retrying `RETRYABLE_STATUSES` and network errors up to `retries` times.
|
|
40
|
+
* Each attempt is signed afresh, since the operator only accepts recent timestamps.
|
|
27
41
|
* Throws the last network error if the operator could not be reached, or if no operator URL is configured.
|
|
28
42
|
*/
|
|
29
|
-
async
|
|
43
|
+
async post(path, body, retries, baseDelayMs) {
|
|
30
44
|
if (!this.url) {
|
|
31
|
-
throw new Error('
|
|
45
|
+
throw new Error('No operator URL is configured');
|
|
32
46
|
}
|
|
33
|
-
const
|
|
34
|
-
|
|
47
|
+
const url = `${this.url}${path}`;
|
|
48
|
+
const serialized = JSON.stringify(body);
|
|
35
49
|
for (let attempt = 0;; attempt++) {
|
|
36
50
|
let retryable;
|
|
37
51
|
try {
|
|
38
|
-
response = await fetch(
|
|
52
|
+
const response = await fetch(url, {
|
|
39
53
|
method: 'POST',
|
|
40
|
-
body,
|
|
54
|
+
body: serialized,
|
|
41
55
|
headers: {
|
|
42
56
|
'Content-Type': 'application/json',
|
|
57
|
+
Authorization: operatorAuthorization('POST', url, body, this.publicKey, this.privateKey),
|
|
43
58
|
},
|
|
44
|
-
signal: AbortSignal.timeout(
|
|
59
|
+
signal: AbortSignal.timeout(OPERATOR_TIMEOUT_MS),
|
|
45
60
|
});
|
|
46
|
-
if (!RETRYABLE_STATUSES.has(response.status) || attempt >=
|
|
47
|
-
|
|
61
|
+
if (!RETRYABLE_STATUSES.has(response.status) || attempt >= retries) {
|
|
62
|
+
return response;
|
|
48
63
|
}
|
|
49
64
|
retryable = response;
|
|
50
65
|
}
|
|
51
66
|
catch (error) {
|
|
52
|
-
if (attempt >=
|
|
67
|
+
if (attempt >= retries) {
|
|
53
68
|
throw error;
|
|
54
69
|
}
|
|
55
70
|
}
|
|
56
|
-
await new Promise(resolve => setTimeout(resolve, retryDelayMs(retryable, attempt)));
|
|
71
|
+
await new Promise(resolve => setTimeout(resolve, retryDelayMs(retryable, attempt, baseDelayMs)));
|
|
57
72
|
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns the organization this node is enrolled in. With an `enrollmentToken` from the dashboard,
|
|
76
|
+
* enrolls the node first; a node that is already enrolled ignores the token. Throws if the node is
|
|
77
|
+
* not enrolled or the operator refuses.
|
|
78
|
+
*/
|
|
79
|
+
async session(enrollmentToken) {
|
|
80
|
+
const response = await this.post('/nodes/session', enrollmentToken ? { enrollmentToken } : {}, OPERATOR_MAX_RETRIES, OPERATOR_BASE_DELAY_MS);
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
throw new Error(`Operator refused this node's session: ${await errorMessage(response)}`);
|
|
83
|
+
}
|
|
84
|
+
return await response.json();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Asks the operator to hold the voucher's amount (or `maxAmount`) on the payer's balance, before
|
|
88
|
+
* running the paid function. An unreachable operator is reported as a 503 refusal.
|
|
89
|
+
*/
|
|
90
|
+
async authorize(voucher) {
|
|
91
|
+
let response;
|
|
92
|
+
try {
|
|
93
|
+
response = await this.post('/payments/authorize', { voucher }, AUTHORIZE_MAX_RETRIES, AUTHORIZE_BASE_DELAY_MS);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error('Failed to reach the operator to authorize a payment', error);
|
|
97
|
+
return { ok: false, status: 503, error: 'Payment operator is unavailable' };
|
|
98
|
+
}
|
|
99
|
+
if (response.ok) {
|
|
100
|
+
return { ok: true };
|
|
101
|
+
}
|
|
102
|
+
// Retries ran out on a transient failure: the caller may try again later.
|
|
103
|
+
const status = RETRYABLE_STATUSES.has(response.status) ? 503 : response.status;
|
|
104
|
+
return { ok: false, status, error: await errorMessage(response) };
|
|
105
|
+
}
|
|
106
|
+
/** Charges a held voucher: its amount, or for inference the reported usage capped at the hold. */
|
|
107
|
+
async capture(payment) {
|
|
108
|
+
await this.settle('/payments/capture', payment);
|
|
109
|
+
}
|
|
110
|
+
/** Releases a held voucher without charging it, for a call that failed or cost nothing. */
|
|
111
|
+
async release(voucher) {
|
|
112
|
+
await this.settle('/payments/release', { voucher });
|
|
113
|
+
}
|
|
114
|
+
/** Logs a refusal instead of throwing: nothing waits on capture or release. Throws only if the operator can't be reached. */
|
|
115
|
+
async settle(path, body) {
|
|
116
|
+
const response = await this.post(path, body, OPERATOR_MAX_RETRIES, OPERATOR_BASE_DELAY_MS);
|
|
58
117
|
if (!response.ok) {
|
|
59
|
-
console.error(`
|
|
118
|
+
console.error(`Operator refused ${path}: ${await errorMessage(response)}`);
|
|
60
119
|
}
|
|
61
120
|
}
|
|
62
121
|
}
|
package/dist/db/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE7C,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE7C,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAc1D,wGAAwG;AACxG,wBAAsB,YAAY,CAAC,QAAQ,GAAE,MAA8B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAI9F;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,iBA+I9C"}
|
package/dist/db/db.js
CHANGED
|
@@ -7,8 +7,11 @@ export const DEFAULT_DATABASE_PATH = './requestscript.db';
|
|
|
7
7
|
* Version 2 added `resource_function.restricted`.
|
|
8
8
|
* Version 3 added `resource.website` and the `description` columns of the resource tables.
|
|
9
9
|
* Version 4 renamed `resource_function_payment_manifest.cost_lamports` to `cost_micro_usdc` (payments moved to USDC).
|
|
10
|
+
* Version 5 added `resource_function.kind` and per-token inference pricing, which made `cost_micro_usdc` nullable.
|
|
11
|
+
* Version 6 moved payments to Stripe: `*_micro_usdc` columns became `*_micro_usd`, and `recipient_address`
|
|
12
|
+
* became `recipient_organization_id`.
|
|
10
13
|
*/
|
|
11
|
-
const SCHEMA_VERSION =
|
|
14
|
+
const SCHEMA_VERSION = 6;
|
|
12
15
|
/** Opens (or creates) the node database and brings its schema up to date. Pass ':memory:' for tests. */
|
|
13
16
|
export async function openDatabase(filename = DEFAULT_DATABASE_PATH) {
|
|
14
17
|
const db = await open({ filename, driver: sqlite3.Database });
|
|
@@ -64,6 +67,7 @@ export async function createTables(db) {
|
|
|
64
67
|
return_type TEXT NOT NULL,
|
|
65
68
|
description TEXT,
|
|
66
69
|
restricted INTEGER NOT NULL DEFAULT 0,
|
|
70
|
+
kind TEXT NOT NULL DEFAULT 'fixed',
|
|
67
71
|
created_at TEXT NOT NULL,
|
|
68
72
|
updated_at TEXT NOT NULL,
|
|
69
73
|
|
|
@@ -89,8 +93,12 @@ export async function createTables(db) {
|
|
|
89
93
|
CREATE TABLE IF NOT EXISTS resource_function_payment_manifest (
|
|
90
94
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
91
95
|
resource_function_id INTEGER NOT NULL,
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
-- Null for inference functions, which are priced per million tokens instead.
|
|
97
|
+
cost_micro_usd INTEGER,
|
|
98
|
+
input_cost_micro_usd_per_million_tokens INTEGER,
|
|
99
|
+
output_cost_micro_usd_per_million_tokens INTEGER,
|
|
100
|
+
-- The hosting node's organization. Null only if a peer advertised the manifest without one.
|
|
101
|
+
recipient_organization_id TEXT,
|
|
94
102
|
created_at TEXT NOT NULL,
|
|
95
103
|
updated_at TEXT NOT NULL,
|
|
96
104
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export { StellariumNode, resolveConfig, type StellariumNodeOptions } from './server.js';
|
|
2
2
|
export type { NodeConfig } from './service.js';
|
|
3
|
-
export type { StellariumResource, StellariumResourceFunction, StellariumResourceFunctionParameter, StellariumResourceFunctionPaymentManifest } from './resource/repository.js';
|
|
4
|
-
export { CombinationResourceInvoker, invocationHash, paymentVoucherPayload, type PaymentVoucher } from './resource/invoker.js';
|
|
3
|
+
export type { StellariumFixedPaymentManifest, StellariumInferencePaymentManifest, StellariumResource, StellariumResourceFunction, StellariumResourceFunctionKind, StellariumResourceFunctionParameter, StellariumResourceFunctionPaymentManifest, } from './resource/repository.js';
|
|
4
|
+
export { CombinationResourceInvoker, inferenceVoucherPayload, invocationHash, paymentVoucherPayload, type InferenceEstimate, type InferencePaymentVoucher, type PaymentVoucher, } from './resource/invoker.js';
|
|
5
|
+
export { inferenceCharge, MAX_TOKENS_PARAMETER, type InferenceResult, type InferenceUsage } from './resource/inference.js';
|
|
6
|
+
export type { FixedPaymentVoucher, InferencePaymentSubmission, InferenceVoucher, PaymentSubmission } from './client/operatorClient.js';
|
|
7
|
+
export { OPERATOR_AUTH_SCHEME, operatorAuthorization, operatorRequestPayload } from './client/operatorAuth.js';
|
|
5
8
|
export { grantHash, grantPayload, grantRenewalPayload, grantRequestPayload, grantsHash, CLOCK_SKEW_TOLERANCE_MS, invocationAuthorizationPayload, MAX_AUTHORIZATION_LIFETIME_MS, MAX_GRANT_CHAIN_LENGTH, MAX_GRANT_LIFETIME_MS, type Capability, type Grant, type GrantRenewalRequest, type GrantRequest, type InvocationAuthorization, } from './grant/grant.js';
|
|
6
9
|
export type { ApproveGrant, GrantApproval, GrantOptions } from './grant/service.js';
|
|
7
10
|
export type { GrantKey } from './grant/repository.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACxF,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACxF,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EACR,8BAA8B,EAC9B,kCAAkC,EAClC,kBAAkB,EAClB,0BAA0B,EAC1B,8BAA8B,EAC9B,mCAAmC,EACnC,yCAAyC,GAC5C,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACH,0BAA0B,EAC1B,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC3H,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEvI,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAE/G,OAAO,EACH,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,uBAAuB,EACvB,8BAA8B,EAC9B,6BAA6B,EAC7B,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,uBAAuB,GAC/B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpF,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { StellariumNode, resolveConfig } from './server.js';
|
|
2
2
|
// The voucher wire format, so the operator and other settlers can test against the real signer.
|
|
3
|
-
export { CombinationResourceInvoker, invocationHash, paymentVoucherPayload } from './resource/invoker.js';
|
|
3
|
+
export { CombinationResourceInvoker, inferenceVoucherPayload, invocationHash, paymentVoucherPayload, } from './resource/invoker.js';
|
|
4
|
+
export { inferenceCharge, MAX_TOKENS_PARAMETER } from './resource/inference.js';
|
|
5
|
+
// The operator request signature, so the operator can test against the real signer.
|
|
6
|
+
export { OPERATOR_AUTH_SCHEME, operatorAuthorization, operatorRequestPayload } from './client/operatorAuth.js';
|
|
4
7
|
// Grant wire format, so other implementations can test against the real signer.
|
|
5
8
|
export { grantHash, grantPayload, grantRenewalPayload, grantRequestPayload, grantsHash, CLOCK_SKEW_TOLERANCE_MS, invocationAuthorizationPayload, MAX_AUTHORIZATION_LIFETIME_MS, MAX_GRANT_CHAIN_LENGTH, MAX_GRANT_LIFETIME_MS, } from './grant/grant.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ResourceFunctionCallParameter } from "requestscript";
|
|
2
|
+
import type { StellariumInferencePaymentManifest, StellariumResourceFunction, StellariumResourceFunctionPaymentManifest } from "./repository.js";
|
|
3
|
+
/** The parameter every inference function takes: the most output tokens the caller allows. */
|
|
4
|
+
export declare const MAX_TOKENS_PARAMETER = "maxTokens";
|
|
5
|
+
/** Token counts an inference function reports for one call. */
|
|
6
|
+
export interface InferenceUsage {
|
|
7
|
+
inputTokens: number;
|
|
8
|
+
outputTokens: number;
|
|
9
|
+
}
|
|
10
|
+
/** What an inference function's `exec` returns. Callers' scripts see only `value`. */
|
|
11
|
+
export interface InferenceResult {
|
|
12
|
+
value: unknown;
|
|
13
|
+
usage: InferenceUsage;
|
|
14
|
+
}
|
|
15
|
+
/** The per-million-token rates a charge is computed from. */
|
|
16
|
+
export interface InferenceRates {
|
|
17
|
+
inputCostMicroUsdPerMillionTokens: number;
|
|
18
|
+
outputCostMicroUsdPerMillionTokens: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function isInferenceManifest(manifest: StellariumResourceFunctionPaymentManifest | undefined): manifest is StellariumInferencePaymentManifest;
|
|
21
|
+
export declare function isInferenceFunction(fn: Pick<StellariumResourceFunction, 'kind'>): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Micro-USD owed for `inputTokens` and `outputTokens` at `rates`, rounded up.
|
|
24
|
+
* Computed exactly in BigInt. Throws if the charge isn't a safe integer.
|
|
25
|
+
* The operator keeps a copy (apps/operator/src/inference.ts) that must stay in sync.
|
|
26
|
+
*/
|
|
27
|
+
export declare function inferenceCharge(rates: InferenceRates, inputTokens: number, outputTokens: number): number;
|
|
28
|
+
/** The call's `maxTokens` value, or undefined unless it is a positive int32. */
|
|
29
|
+
export declare function parseMaxTokens(parameters: ResourceFunctionCallParameter[]): number | undefined;
|
|
30
|
+
/** The usage an inference `exec` reported, or undefined if it isn't two nonnegative safe integers. */
|
|
31
|
+
export declare function parseInferenceResult(result: unknown): InferenceResult | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Throws unless an inference function declares an int32 `maxTokens` parameter and, when paid,
|
|
34
|
+
* an inference payment manifest with nonnegative integer rates and an `estimateInputTokens` function.
|
|
35
|
+
* A function that isn't an inference function may not carry an inference manifest.
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateInferenceFunction(fn: StellariumResourceFunction): void;
|
|
38
|
+
//# sourceMappingURL=inference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/resource/inference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,kCAAkC,EAAE,0BAA0B,EAAE,yCAAyC,EAAE,MAAM,iBAAiB,CAAC;AAEjJ,8FAA8F;AAC9F,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAIhD,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,sFAAsF;AACtF,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,cAAc,CAAC;CACzB;AAED,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC3B,iCAAiC,EAAE,MAAM,CAAC;IAC1C,kCAAkC,EAAE,MAAM,CAAC;CAC9C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,yCAAyC,GAAG,SAAS,GAAG,QAAQ,IAAI,kCAAkC,CAEnJ;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,IAAI,CAAC,0BAA0B,EAAE,MAAM,CAAC,GAAG,OAAO,CAEzF;AAMD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAQxG;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,UAAU,EAAE,6BAA6B,EAAE,GAAG,MAAM,GAAG,SAAS,CAG9F;AAED,sGAAsG;AACtG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAajF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,0BAA0B,GAAG,IAAI,CAsB9E"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** The parameter every inference function takes: the most output tokens the caller allows. */
|
|
2
|
+
export const MAX_TOKENS_PARAMETER = 'maxTokens';
|
|
3
|
+
const INT32_MAX = 2_147_483_647;
|
|
4
|
+
export function isInferenceManifest(manifest) {
|
|
5
|
+
return typeof manifest === 'object' && manifest !== null && 'inputCostMicroUsdPerMillionTokens' in manifest;
|
|
6
|
+
}
|
|
7
|
+
export function isInferenceFunction(fn) {
|
|
8
|
+
return fn.kind === 'inference';
|
|
9
|
+
}
|
|
10
|
+
function isNonnegativeSafeInteger(value) {
|
|
11
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Micro-USD owed for `inputTokens` and `outputTokens` at `rates`, rounded up.
|
|
15
|
+
* Computed exactly in BigInt. Throws if the charge isn't a safe integer.
|
|
16
|
+
* The operator keeps a copy (apps/operator/src/inference.ts) that must stay in sync.
|
|
17
|
+
*/
|
|
18
|
+
export function inferenceCharge(rates, inputTokens, outputTokens) {
|
|
19
|
+
const micros = BigInt(inputTokens) * BigInt(rates.inputCostMicroUsdPerMillionTokens)
|
|
20
|
+
+ BigInt(outputTokens) * BigInt(rates.outputCostMicroUsdPerMillionTokens);
|
|
21
|
+
const charge = (micros + 999999n) / 1000000n;
|
|
22
|
+
if (charge > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
23
|
+
throw new Error('Inference charge exceeds the largest safe integer');
|
|
24
|
+
}
|
|
25
|
+
return Number(charge);
|
|
26
|
+
}
|
|
27
|
+
/** The call's `maxTokens` value, or undefined unless it is a positive int32. */
|
|
28
|
+
export function parseMaxTokens(parameters) {
|
|
29
|
+
const value = parameters.find(parameter => parameter.name === MAX_TOKENS_PARAMETER)?.value;
|
|
30
|
+
return Number.isInteger(value) && value > 0 && value <= INT32_MAX ? value : undefined;
|
|
31
|
+
}
|
|
32
|
+
/** The usage an inference `exec` reported, or undefined if it isn't two nonnegative safe integers. */
|
|
33
|
+
export function parseInferenceResult(result) {
|
|
34
|
+
if (typeof result !== 'object' || result === null || !('usage' in result)) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const { value, usage } = result;
|
|
38
|
+
if (typeof usage !== 'object' || usage === null) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const { inputTokens, outputTokens } = usage;
|
|
42
|
+
if (!isNonnegativeSafeInteger(inputTokens) || !isNonnegativeSafeInteger(outputTokens)) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return { value, usage: { inputTokens, outputTokens } };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Throws unless an inference function declares an int32 `maxTokens` parameter and, when paid,
|
|
49
|
+
* an inference payment manifest with nonnegative integer rates and an `estimateInputTokens` function.
|
|
50
|
+
* A function that isn't an inference function may not carry an inference manifest.
|
|
51
|
+
*/
|
|
52
|
+
export function validateInferenceFunction(fn) {
|
|
53
|
+
if (!isInferenceFunction(fn)) {
|
|
54
|
+
if (isInferenceManifest(fn.paymentManifest)) {
|
|
55
|
+
throw new Error(`Function ${fn.name} has per-token pricing but is not declared with kind 'inference'`);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const maxTokens = fn.parameters.find(parameter => parameter.name === MAX_TOKENS_PARAMETER);
|
|
60
|
+
if (maxTokens?.type !== 'int32') {
|
|
61
|
+
throw new Error(`Inference function ${fn.name} must take a '${MAX_TOKENS_PARAMETER}: int32' parameter`);
|
|
62
|
+
}
|
|
63
|
+
if (!fn.paymentManifest) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!isInferenceManifest(fn.paymentManifest)
|
|
67
|
+
|| !isNonnegativeSafeInteger(fn.paymentManifest.inputCostMicroUsdPerMillionTokens)
|
|
68
|
+
|| !isNonnegativeSafeInteger(fn.paymentManifest.outputCostMicroUsdPerMillionTokens)) {
|
|
69
|
+
throw new Error(`Inference function ${fn.name} must price input and output tokens as nonnegative integer micro-USD per million tokens`);
|
|
70
|
+
}
|
|
71
|
+
if (typeof fn.estimateInputTokens !== 'function') {
|
|
72
|
+
throw new Error(`Paid inference function ${fn.name} must declare estimateInputTokens`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import { Resource, ResourceFunctionCallParameter, ResourceInvoker } from "requestscript";
|
|
2
2
|
import type { GrantService } from "../grant/service.js";
|
|
3
|
-
import {
|
|
3
|
+
import { type InferenceUsage } from "./inference.js";
|
|
4
|
+
import { ResourceRepository, type StellariumInferencePaymentManifest } from "./repository.js";
|
|
4
5
|
export interface PaymentVoucher {
|
|
5
6
|
requestId: string;
|
|
6
7
|
invocationId: string;
|
|
7
8
|
amount: number;
|
|
8
|
-
|
|
9
|
+
recipientOrganizationId: string;
|
|
9
10
|
signature: string;
|
|
10
11
|
expiresAt: string;
|
|
11
12
|
invocationHash: string;
|
|
12
13
|
publicKey: string;
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* A voucher for an inference function. It signs the provider's per-million-token rates and the call's
|
|
17
|
+
* `maxTokens` instead of an amount: the operator charges the usage the provider reports at those rates,
|
|
18
|
+
* up to `maxAmount`.
|
|
19
|
+
*/
|
|
20
|
+
export interface InferencePaymentVoucher {
|
|
21
|
+
kind: 'inference';
|
|
22
|
+
requestId: string;
|
|
23
|
+
invocationId: string;
|
|
24
|
+
maxAmount: number;
|
|
25
|
+
inputCostMicroUsdPerMillionTokens: number;
|
|
26
|
+
outputCostMicroUsdPerMillionTokens: number;
|
|
27
|
+
maxTokens: number;
|
|
28
|
+
recipientOrganizationId: string;
|
|
29
|
+
signature: string;
|
|
30
|
+
expiresAt: string;
|
|
31
|
+
invocationHash: string;
|
|
32
|
+
publicKey: string;
|
|
33
|
+
}
|
|
34
|
+
/** What a provider's `POST /v1/run/resource/estimate` answers. */
|
|
35
|
+
export interface InferenceEstimate {
|
|
36
|
+
inputTokens: number;
|
|
37
|
+
maxAmount: number;
|
|
38
|
+
}
|
|
14
39
|
/**
|
|
15
40
|
* Hash binding a voucher to one function call. Providers recompute it from the
|
|
16
41
|
* request they receive and compare it to `voucher.invocationHash`.
|
|
@@ -25,29 +50,57 @@ export declare function paymentVoucherPayload(voucher: Omit<PaymentVoucher, "sig
|
|
|
25
50
|
requestId: string;
|
|
26
51
|
invocationId: string;
|
|
27
52
|
amount: number;
|
|
28
|
-
|
|
53
|
+
recipientOrganizationId: string;
|
|
29
54
|
expiresAt: string;
|
|
30
55
|
invocationHash: string;
|
|
31
56
|
publicKey: string;
|
|
32
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* The object `createInferenceVoucher` signs: every inference voucher field except `signature`.
|
|
60
|
+
* Key order is part of the signed bytes.
|
|
61
|
+
*/
|
|
62
|
+
export declare function inferenceVoucherPayload(voucher: Omit<InferencePaymentVoucher, "signature">): {
|
|
63
|
+
kind: "inference";
|
|
64
|
+
requestId: string;
|
|
65
|
+
invocationId: string;
|
|
66
|
+
maxAmount: number;
|
|
67
|
+
inputCostMicroUsdPerMillionTokens: number;
|
|
68
|
+
outputCostMicroUsdPerMillionTokens: number;
|
|
69
|
+
maxTokens: number;
|
|
70
|
+
recipientOrganizationId: string;
|
|
71
|
+
expiresAt: string;
|
|
72
|
+
invocationHash: string;
|
|
73
|
+
publicKey: string;
|
|
74
|
+
};
|
|
75
|
+
export declare function isInferenceVoucher(voucher: PaymentVoucher | InferencePaymentVoucher): voucher is InferencePaymentVoucher;
|
|
76
|
+
export declare const PAYMENT_VOUCHER_LIFETIME_MS: number;
|
|
77
|
+
/** Inference can run for minutes, and the operator refuses a voucher that expired before the provider settled it. */
|
|
78
|
+
export declare const INFERENCE_VOUCHER_LIFETIME_MS: number;
|
|
33
79
|
export declare const EXTERNAL_INVOKE_MAX_RETRIES = 3;
|
|
34
80
|
export declare const EXTERNAL_INVOKE_BASE_DELAY_MS = 500;
|
|
35
81
|
/** Per attempt. A timed-out attempt is retried like a network error. */
|
|
36
82
|
export declare const EXTERNAL_INVOKE_TIMEOUT_MS = 30000;
|
|
83
|
+
/** Per attempt, for calls to inference functions. Every attempt fits within `INFERENCE_VOUCHER_LIFETIME_MS`. */
|
|
84
|
+
export declare const INFERENCE_INVOKE_TIMEOUT_MS = 120000;
|
|
37
85
|
export declare class CombinationResourceInvoker implements ResourceInvoker {
|
|
38
86
|
private readonly resourceRepository;
|
|
39
|
-
private readonly
|
|
87
|
+
private readonly costLimitMicroUsd;
|
|
40
88
|
private readonly publicKey;
|
|
41
89
|
private readonly privateKey;
|
|
42
90
|
private readonly grantService?;
|
|
43
|
-
|
|
44
|
-
|
|
91
|
+
private readonly inferenceCostLimitMicroUsd;
|
|
92
|
+
/**
|
|
93
|
+
* Without a `grantService`, calls to restricted remote functions fail.
|
|
94
|
+
* `inferenceCostLimitMicroUsd` caps an inference voucher's `maxAmount`, and defaults to `costLimitMicroUsd`.
|
|
95
|
+
*/
|
|
96
|
+
constructor(resourceRepository: ResourceRepository, costLimitMicroUsd: number, publicKey: string, privateKey: string, grantService?: GrantService | undefined, inferenceCostLimitMicroUsd?: number);
|
|
45
97
|
/**
|
|
46
98
|
* Invoke a function on a resource.
|
|
47
99
|
* If the resource has a baseUrl, it will be invoked as a remote function.
|
|
48
100
|
* If the function is restricted, it attaches an authorization from a held grant.
|
|
49
101
|
* If the resource has a paymentManifest, it will create a payment voucher and pass it to the resource.
|
|
50
|
-
*
|
|
102
|
+
* A paid inference function is first priced by the provider's estimate endpoint.
|
|
103
|
+
* Otherwise, it will be invoked as a local function. A local inference function's usage is returned beside its value.
|
|
51
104
|
*
|
|
52
105
|
* @param resource - The resource to invoke
|
|
53
106
|
* @param functionName - The name of the function to invoke
|
|
@@ -59,7 +112,11 @@ export declare class CombinationResourceInvoker implements ResourceInvoker {
|
|
|
59
112
|
error: {
|
|
60
113
|
message: string;
|
|
61
114
|
} | null;
|
|
115
|
+
usage?: InferenceUsage;
|
|
62
116
|
}>;
|
|
63
|
-
|
|
117
|
+
/** Asks the provider what a call to a paid inference function will cost at most. */
|
|
118
|
+
private estimate;
|
|
119
|
+
createPaymentVoucher(recipientOrganizationId: string, amount: number, resourcePath: string, resourceName: string, functionName: string, parameters: ResourceFunctionCallParameter[]): PaymentVoucher;
|
|
120
|
+
createInferenceVoucher(manifest: StellariumInferencePaymentManifest, maxAmount: number, maxTokens: number, resourcePath: string, resourceName: string, functionName: string, parameters: ResourceFunctionCallParameter[]): InferencePaymentVoucher;
|
|
64
121
|
}
|
|
65
122
|
//# sourceMappingURL=invoker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/resource/invoker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/resource/invoker.ts"],"names":[],"mappings":"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"}
|