stellarium-ts 0.17.0 → 0.18.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/operatorClient.d.ts +36 -1
- package/dist/client/operatorClient.d.ts.map +1 -1
- package/dist/client/operatorClient.js +30 -5
- package/dist/client/runTokens.d.ts +23 -0
- package/dist/client/runTokens.d.ts.map +1 -0
- package/dist/client/runTokens.js +34 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/resource/inference.d.ts +2 -0
- package/dist/resource/inference.d.ts.map +1 -1
- package/dist/resource/inference.js +10 -0
- package/dist/resource/invoker.d.ts +37 -3
- package/dist/resource/invoker.d.ts.map +1 -1
- package/dist/resource/invoker.js +91 -24
- package/dist/resource/settlement.d.ts +25 -0
- package/dist/resource/settlement.d.ts.map +1 -0
- package/dist/resource/settlement.js +59 -0
- package/dist/routes.d.ts +16 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +84 -66
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -1
- package/dist/service.d.ts +11 -4
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +6 -1
- package/dist/tests/integration/network.test.js +18 -14
- package/dist/tests/resource/invoker.test.js +19 -0
- package/dist/tests/routes.test.js +94 -2
- package/package.json +3 -2
|
@@ -9,6 +9,7 @@ export interface FixedPaymentVoucher {
|
|
|
9
9
|
expiresAt: string;
|
|
10
10
|
invocationHash: string;
|
|
11
11
|
publicKey: string;
|
|
12
|
+
runId?: string;
|
|
12
13
|
}
|
|
13
14
|
export interface InferenceVoucher {
|
|
14
15
|
kind: 'inference';
|
|
@@ -23,6 +24,7 @@ export interface InferenceVoucher {
|
|
|
23
24
|
expiresAt: string;
|
|
24
25
|
invocationHash: string;
|
|
25
26
|
publicKey: string;
|
|
27
|
+
runId?: string;
|
|
26
28
|
}
|
|
27
29
|
export interface FixedPaymentSubmission {
|
|
28
30
|
voucher: FixedPaymentVoucher;
|
|
@@ -43,6 +45,23 @@ export type AuthorizeResult = {
|
|
|
43
45
|
status: number;
|
|
44
46
|
error: string;
|
|
45
47
|
};
|
|
48
|
+
/** What a node sends to authorize a script run billed to an API client. Matches apps/operator/src/runs/runService.ts. */
|
|
49
|
+
export interface RunAuthorizationRequest {
|
|
50
|
+
/** The run token the caller presented. */
|
|
51
|
+
token: string;
|
|
52
|
+
runId: string;
|
|
53
|
+
source: string;
|
|
54
|
+
}
|
|
55
|
+
/** The operator's hold for a run: up to `heldMicroUsd` for the script's tokens and its paid calls together. */
|
|
56
|
+
export type RunAuthorizeResult = {
|
|
57
|
+
ok: true;
|
|
58
|
+
heldMicroUsd: number;
|
|
59
|
+
maxTokens: number;
|
|
60
|
+
} | {
|
|
61
|
+
ok: false;
|
|
62
|
+
status: number;
|
|
63
|
+
error: string;
|
|
64
|
+
};
|
|
46
65
|
export declare const OPERATOR_MAX_RETRIES = 5;
|
|
47
66
|
/** Authorization runs while the caller waits, so it gives up much sooner than capture and release. */
|
|
48
67
|
export declare const AUTHORIZE_MAX_RETRIES = 2;
|
|
@@ -67,7 +86,7 @@ export declare class OperatorClient {
|
|
|
67
86
|
* enrolls the node first; a node that is already enrolled ignores the token. Throws if the node is
|
|
68
87
|
* not enrolled or the operator refuses.
|
|
69
88
|
*/
|
|
70
|
-
session(enrollmentToken?: string): Promise<{
|
|
89
|
+
session(enrollmentToken?: string, baseUrl?: string): Promise<{
|
|
71
90
|
organizationId: string;
|
|
72
91
|
}>;
|
|
73
92
|
/**
|
|
@@ -75,6 +94,22 @@ export declare class OperatorClient {
|
|
|
75
94
|
* running the paid function. An unreachable operator is reported as a 503 refusal.
|
|
76
95
|
*/
|
|
77
96
|
authorize(voucher: FixedPaymentVoucher | InferenceVoucher): Promise<AuthorizeResult>;
|
|
97
|
+
/**
|
|
98
|
+
* Asks the operator to hold a script run's cost on the paying API client's organization, before running
|
|
99
|
+
* it. An unreachable operator is reported as a 503 refusal.
|
|
100
|
+
*/
|
|
101
|
+
authorizeRun(request: RunAuthorizationRequest): Promise<RunAuthorizeResult>;
|
|
102
|
+
/** Charges a held run for the tokens its script executed, and releases the rest of its hold. */
|
|
103
|
+
captureRun(request: {
|
|
104
|
+
runId: string;
|
|
105
|
+
tokens: number;
|
|
106
|
+
}): Promise<void>;
|
|
107
|
+
/** Releases a held run without charging it, for a script this node failed to run. */
|
|
108
|
+
releaseRun(request: {
|
|
109
|
+
runId: string;
|
|
110
|
+
}): Promise<void>;
|
|
111
|
+
/** Authorization runs while the caller waits, so it retries briefly and reports an unreachable operator as 503. */
|
|
112
|
+
private hold;
|
|
78
113
|
/** Charges a held voucher: its amount, or for inference the reported usage capped at the hold. */
|
|
79
114
|
capture(payment: PaymentSubmission): Promise<void>;
|
|
80
115
|
/** Releases a held voucher without charging it, for a call that failed or cost nothing. */
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"operatorClient.d.ts","sourceRoot":"","sources":["../../src/client/operatorClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -76,8 +76,9 @@ export class OperatorClient {
|
|
|
76
76
|
* enrolls the node first; a node that is already enrolled ignores the token. Throws if the node is
|
|
77
77
|
* not enrolled or the operator refuses.
|
|
78
78
|
*/
|
|
79
|
-
async session(enrollmentToken) {
|
|
80
|
-
const
|
|
79
|
+
async session(enrollmentToken, baseUrl) {
|
|
80
|
+
const body = { ...(enrollmentToken ? { enrollmentToken } : {}), ...(baseUrl ? { baseUrl } : {}) };
|
|
81
|
+
const response = await this.post('/nodes/session', body, OPERATOR_MAX_RETRIES, OPERATOR_BASE_DELAY_MS);
|
|
81
82
|
if (!response.ok) {
|
|
82
83
|
throw new Error(`Operator refused this node's session: ${await errorMessage(response)}`);
|
|
83
84
|
}
|
|
@@ -88,16 +89,40 @@ export class OperatorClient {
|
|
|
88
89
|
* running the paid function. An unreachable operator is reported as a 503 refusal.
|
|
89
90
|
*/
|
|
90
91
|
async authorize(voucher) {
|
|
92
|
+
const result = await this.hold('/payments/authorize', { voucher });
|
|
93
|
+
return result.ok ? { ok: true } : result;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Asks the operator to hold a script run's cost on the paying API client's organization, before running
|
|
97
|
+
* it. An unreachable operator is reported as a 503 refusal.
|
|
98
|
+
*/
|
|
99
|
+
async authorizeRun(request) {
|
|
100
|
+
const result = await this.hold('/runs/authorize', request);
|
|
101
|
+
if (!result.ok)
|
|
102
|
+
return result;
|
|
103
|
+
const { heldMicroUsd, maxTokens } = result.body;
|
|
104
|
+
return { ok: true, heldMicroUsd, maxTokens };
|
|
105
|
+
}
|
|
106
|
+
/** Charges a held run for the tokens its script executed, and releases the rest of its hold. */
|
|
107
|
+
async captureRun(request) {
|
|
108
|
+
await this.settle('/runs/capture', request);
|
|
109
|
+
}
|
|
110
|
+
/** Releases a held run without charging it, for a script this node failed to run. */
|
|
111
|
+
async releaseRun(request) {
|
|
112
|
+
await this.settle('/runs/release', request);
|
|
113
|
+
}
|
|
114
|
+
/** Authorization runs while the caller waits, so it retries briefly and reports an unreachable operator as 503. */
|
|
115
|
+
async hold(path, body) {
|
|
91
116
|
let response;
|
|
92
117
|
try {
|
|
93
|
-
response = await this.post(
|
|
118
|
+
response = await this.post(path, body, AUTHORIZE_MAX_RETRIES, AUTHORIZE_BASE_DELAY_MS);
|
|
94
119
|
}
|
|
95
120
|
catch (error) {
|
|
96
|
-
console.error(
|
|
121
|
+
console.error(`Failed to reach the operator for ${path}`, error);
|
|
97
122
|
return { ok: false, status: 503, error: 'Payment operator is unavailable' };
|
|
98
123
|
}
|
|
99
124
|
if (response.ok) {
|
|
100
|
-
return { ok: true };
|
|
125
|
+
return { ok: true, body: await response.json().catch(() => undefined) };
|
|
101
126
|
}
|
|
102
127
|
// Retries ran out on a transient failure: the caller may try again later.
|
|
103
128
|
const status = RETRYABLE_STATUSES.has(response.status) ? 503 : response.status;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type JWTVerifyGetKey } from "jose";
|
|
2
|
+
/** The `iss` of every run token. Copied from RUN_TOKEN_ISSUER in apps/operator/src/runs/tokens.ts. */
|
|
3
|
+
export declare const RUN_TOKEN_ISSUER = "stellarium";
|
|
4
|
+
/** Who a run token lets run scripts on this node, and which organization pays. */
|
|
5
|
+
export interface RunTokenClaims {
|
|
6
|
+
clientId: string;
|
|
7
|
+
organizationId: string;
|
|
8
|
+
}
|
|
9
|
+
/** Whether `token` has the three base64url segments of a JWT, as opposed to an API key. */
|
|
10
|
+
export declare function looksLikeJwt(token: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Verifies the run tokens API clients get from the operator's `POST /v1/oauth/token`, against the
|
|
13
|
+
* operator's published keys. A token is only valid at the node whose public key is its audience.
|
|
14
|
+
*/
|
|
15
|
+
export declare class RunTokenVerifier {
|
|
16
|
+
private readonly nodePublicKey;
|
|
17
|
+
private readonly keys;
|
|
18
|
+
/** `keys` replaces fetching `{operatorUrl}/.well-known/jwks.json`, in tests. */
|
|
19
|
+
constructor(operatorUrl: string, nodePublicKey: string, keys?: JWTVerifyGetKey);
|
|
20
|
+
/** The token's claims, or undefined unless it is signed by the operator, unexpired and addressed to this node. */
|
|
21
|
+
verify(token: string): Promise<RunTokenClaims | undefined>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=runTokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTokens.d.ts","sourceRoot":"","sources":["../../src/client/runTokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,eAAe,EAAa,MAAM,MAAM,CAAC;AAE3E,sGAAsG;AACtG,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAIQ,OAAO,CAAC,QAAQ,CAAC,aAAa;IAH/D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IAEvC,gFAAgF;IAChF,YAAY,WAAW,EAAE,MAAM,EAAmB,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,eAAe,EAG9F;IAED,kHAAkH;IAC5G,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAU/D;CACJ"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
2
|
+
/** The `iss` of every run token. Copied from RUN_TOKEN_ISSUER in apps/operator/src/runs/tokens.ts. */
|
|
3
|
+
export const RUN_TOKEN_ISSUER = 'stellarium';
|
|
4
|
+
/** Whether `token` has the three base64url segments of a JWT, as opposed to an API key. */
|
|
5
|
+
export function looksLikeJwt(token) {
|
|
6
|
+
return /^[\w-]+\.[\w-]+\.[\w-]+$/.test(token);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Verifies the run tokens API clients get from the operator's `POST /v1/oauth/token`, against the
|
|
10
|
+
* operator's published keys. A token is only valid at the node whose public key is its audience.
|
|
11
|
+
*/
|
|
12
|
+
export class RunTokenVerifier {
|
|
13
|
+
nodePublicKey;
|
|
14
|
+
keys;
|
|
15
|
+
/** `keys` replaces fetching `{operatorUrl}/.well-known/jwks.json`, in tests. */
|
|
16
|
+
constructor(operatorUrl, nodePublicKey, keys) {
|
|
17
|
+
this.nodePublicKey = nodePublicKey;
|
|
18
|
+
// Cached, and refetched when a token names a key it doesn't have.
|
|
19
|
+
this.keys = keys ?? createRemoteJWKSet(new URL(`${operatorUrl}/.well-known/jwks.json`));
|
|
20
|
+
}
|
|
21
|
+
/** The token's claims, or undefined unless it is signed by the operator, unexpired and addressed to this node. */
|
|
22
|
+
async verify(token) {
|
|
23
|
+
try {
|
|
24
|
+
const { payload } = await jwtVerify(token, this.keys, { issuer: RUN_TOKEN_ISSUER, audience: this.nodePublicKey, algorithms: ['EdDSA'] });
|
|
25
|
+
if (typeof payload.sub !== 'string' || typeof payload.org !== 'string') {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return { clientId: payload.sub, organizationId: payload.org };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { StellariumNode, resolveConfig, type StellariumNodeOptions } from './server.js';
|
|
2
2
|
export type { NodeConfig } from './service.js';
|
|
3
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';
|
|
4
|
+
export { CombinationResourceInvoker, inferenceVoucherPayload, invocationHash, paymentVoucherPayload, type RunContext, type InferenceEstimate, type InferencePaymentVoucher, type PaymentVoucher, } from './resource/invoker.js';
|
|
5
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';
|
|
6
|
+
export type { FixedPaymentVoucher, InferencePaymentSubmission, InferenceVoucher, PaymentSubmission, RunAuthorizationRequest } from './client/operatorClient.js';
|
|
7
|
+
export { RUN_TOKEN_ISSUER, RunTokenVerifier, type RunTokenClaims } from './client/runTokens.js';
|
|
7
8
|
export { OPERATOR_AUTH_SCHEME, operatorAuthorization, operatorRequestPayload } from './client/operatorAuth.js';
|
|
8
9
|
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';
|
|
9
10
|
export type { ApproveGrant, GrantApproval, GrantOptions } from './grant/service.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,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;
|
|
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,UAAU,EACf,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,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAEhK,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEhG,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
|
@@ -2,6 +2,8 @@ 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
3
|
export { CombinationResourceInvoker, inferenceVoucherPayload, invocationHash, paymentVoucherPayload, } from './resource/invoker.js';
|
|
4
4
|
export { inferenceCharge, MAX_TOKENS_PARAMETER } from './resource/inference.js';
|
|
5
|
+
// Run token verification, so the operator can test its tokens against the real verifier.
|
|
6
|
+
export { RUN_TOKEN_ISSUER, RunTokenVerifier } from './client/runTokens.js';
|
|
5
7
|
// The operator request signature, so the operator can test against the real signer.
|
|
6
8
|
export { OPERATOR_AUTH_SCHEME, operatorAuthorization, operatorRequestPayload } from './client/operatorAuth.js';
|
|
7
9
|
// Grant wire format, so other implementations can test against the real signer.
|
|
@@ -27,6 +27,8 @@ export declare function isInferenceFunction(fn: Pick<StellariumResourceFunction,
|
|
|
27
27
|
export declare function inferenceCharge(rates: InferenceRates, inputTokens: number, outputTokens: number): number;
|
|
28
28
|
/** The call's `maxTokens` value, or undefined unless it is a positive int32. */
|
|
29
29
|
export declare function parseMaxTokens(parameters: ResourceFunctionCallParameter[]): number | undefined;
|
|
30
|
+
/** The function's own input-token estimate, or undefined if its estimator failed or returned something other than a count. */
|
|
31
|
+
export declare function estimateInputTokens(fn: StellariumResourceFunction, parameters: ResourceFunctionCallParameter[]): Promise<number | undefined>;
|
|
30
32
|
/** The usage an inference `exec` reported, or undefined if it isn't two nonnegative safe integers. */
|
|
31
33
|
export declare function parseInferenceResult(result: unknown): InferenceResult | undefined;
|
|
32
34
|
/**
|
|
@@ -1 +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"}
|
|
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,8HAA8H;AAC9H,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,0BAA0B,EAAE,UAAU,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAOlJ;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"}
|
|
@@ -29,6 +29,16 @@ export function parseMaxTokens(parameters) {
|
|
|
29
29
|
const value = parameters.find(parameter => parameter.name === MAX_TOKENS_PARAMETER)?.value;
|
|
30
30
|
return Number.isInteger(value) && value > 0 && value <= INT32_MAX ? value : undefined;
|
|
31
31
|
}
|
|
32
|
+
/** The function's own input-token estimate, or undefined if its estimator failed or returned something other than a count. */
|
|
33
|
+
export async function estimateInputTokens(fn, parameters) {
|
|
34
|
+
try {
|
|
35
|
+
const inputTokens = await fn.estimateInputTokens?.(parameters);
|
|
36
|
+
return Number.isSafeInteger(inputTokens) && inputTokens >= 0 ? inputTokens : undefined;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
32
42
|
/** The usage an inference `exec` reported, or undefined if it isn't two nonnegative safe integers. */
|
|
33
43
|
export function parseInferenceResult(result) {
|
|
34
44
|
if (typeof result !== 'object' || result === null || !('usage' in result)) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Resource, ResourceFunctionCallParameter, ResourceInvoker } from "requestscript";
|
|
2
|
+
import type { OperatorClient } from "../client/operatorClient.js";
|
|
2
3
|
import type { GrantService } from "../grant/service.js";
|
|
3
4
|
import { type InferenceUsage } from "./inference.js";
|
|
4
5
|
import { ResourceRepository, type StellariumInferencePaymentManifest } from "./repository.js";
|
|
@@ -11,6 +12,8 @@ export interface PaymentVoucher {
|
|
|
11
12
|
expiresAt: string;
|
|
12
13
|
invocationHash: string;
|
|
13
14
|
publicKey: string;
|
|
15
|
+
/** Set for a call made by a script run billed to an API client: the run's hold pays instead of this node's organization. */
|
|
16
|
+
runId?: string;
|
|
14
17
|
}
|
|
15
18
|
/**
|
|
16
19
|
* A voucher for an inference function. It signs the provider's per-million-token rates and the call's
|
|
@@ -30,6 +33,8 @@ export interface InferencePaymentVoucher {
|
|
|
30
33
|
expiresAt: string;
|
|
31
34
|
invocationHash: string;
|
|
32
35
|
publicKey: string;
|
|
36
|
+
/** Set for a call made by a script run billed to an API client: the run's hold pays instead of this node's organization. */
|
|
37
|
+
runId?: string;
|
|
33
38
|
}
|
|
34
39
|
/** What a provider's `POST /v1/run/resource/estimate` answers. */
|
|
35
40
|
export interface InferenceEstimate {
|
|
@@ -54,12 +59,14 @@ export declare function paymentVoucherPayload(voucher: Omit<PaymentVoucher, "sig
|
|
|
54
59
|
expiresAt: string;
|
|
55
60
|
invocationHash: string;
|
|
56
61
|
publicKey: string;
|
|
62
|
+
runId?: string;
|
|
57
63
|
};
|
|
58
64
|
/**
|
|
59
65
|
* The object `createInferenceVoucher` signs: every inference voucher field except `signature`.
|
|
60
66
|
* Key order is part of the signed bytes.
|
|
61
67
|
*/
|
|
62
68
|
export declare function inferenceVoucherPayload(voucher: Omit<InferencePaymentVoucher, "signature">): {
|
|
69
|
+
runId?: string;
|
|
63
70
|
kind: "inference";
|
|
64
71
|
requestId: string;
|
|
65
72
|
invocationId: string;
|
|
@@ -82,6 +89,16 @@ export declare const EXTERNAL_INVOKE_BASE_DELAY_MS = 500;
|
|
|
82
89
|
export declare const EXTERNAL_INVOKE_TIMEOUT_MS = 30000;
|
|
83
90
|
/** Per attempt, for calls to inference functions. Every attempt fits within `INFERENCE_VOUCHER_LIFETIME_MS`. */
|
|
84
91
|
export declare const INFERENCE_INVOKE_TIMEOUT_MS = 120000;
|
|
92
|
+
/** A script run billed to another organization's API client. Its paid calls draw on the run's hold. */
|
|
93
|
+
export interface RunContext {
|
|
94
|
+
runId: string;
|
|
95
|
+
}
|
|
96
|
+
/** How a node settles its own paid functions when a billed run calls them. */
|
|
97
|
+
export interface LocalSettlement {
|
|
98
|
+
operatorClient: OperatorClient;
|
|
99
|
+
/** The organization this node's functions pay. */
|
|
100
|
+
organizationId?: string;
|
|
101
|
+
}
|
|
85
102
|
export declare class CombinationResourceInvoker implements ResourceInvoker {
|
|
86
103
|
private readonly resourceRepository;
|
|
87
104
|
private readonly costLimitMicroUsd;
|
|
@@ -89,11 +106,19 @@ export declare class CombinationResourceInvoker implements ResourceInvoker {
|
|
|
89
106
|
private readonly privateKey;
|
|
90
107
|
private readonly grantService?;
|
|
91
108
|
private readonly inferenceCostLimitMicroUsd;
|
|
109
|
+
private readonly localSettlement?;
|
|
92
110
|
/**
|
|
93
111
|
* Without a `grantService`, calls to restricted remote functions fail.
|
|
94
112
|
* `inferenceCostLimitMicroUsd` caps an inference voucher's `maxAmount`, and defaults to `costLimitMicroUsd`.
|
|
113
|
+
* Without `localSettlement`, a billed run can't call this node's own paid functions.
|
|
114
|
+
*/
|
|
115
|
+
constructor(resourceRepository: ResourceRepository, costLimitMicroUsd: number, publicKey: string, privateKey: string, grantService?: GrantService | undefined, inferenceCostLimitMicroUsd?: number, localSettlement?: LocalSettlement | undefined);
|
|
116
|
+
/**
|
|
117
|
+
* An invoker for one billed run. Its paid calls, remote or to this node's own paid functions, carry
|
|
118
|
+
* the run's id, so the run's hold pays for them. The run's hold limits what they cost, in place of the
|
|
119
|
+
* cost limits.
|
|
95
120
|
*/
|
|
96
|
-
|
|
121
|
+
forRun(run: RunContext): ResourceInvoker;
|
|
97
122
|
/**
|
|
98
123
|
* Invoke a function on a resource.
|
|
99
124
|
* If the resource has a baseUrl, it will be invoked as a remote function.
|
|
@@ -114,9 +139,18 @@ export declare class CombinationResourceInvoker implements ResourceInvoker {
|
|
|
114
139
|
} | null;
|
|
115
140
|
usage?: InferenceUsage;
|
|
116
141
|
}>;
|
|
142
|
+
private invokeIn;
|
|
143
|
+
private execLocal;
|
|
144
|
+
/**
|
|
145
|
+
* Calls one of this node's paid functions for a billed run: signs a voucher with the run's id that pays
|
|
146
|
+
* this node's organization, then authorizes, runs and settles it as `POST /v1/run/resource` would.
|
|
147
|
+
*/
|
|
148
|
+
private invokeLocalPaid;
|
|
117
149
|
/** Asks the provider what a call to a paid inference function will cost at most. */
|
|
118
150
|
private estimate;
|
|
119
|
-
|
|
120
|
-
|
|
151
|
+
/** With `runId`, the voucher is paid from that run's hold. */
|
|
152
|
+
createPaymentVoucher(recipientOrganizationId: string, amount: number, resourcePath: string, resourceName: string, functionName: string, parameters: ResourceFunctionCallParameter[], runId?: string): PaymentVoucher;
|
|
153
|
+
/** With `runId`, the voucher is paid from that run's hold. */
|
|
154
|
+
createInferenceVoucher(manifest: StellariumInferencePaymentManifest, maxAmount: number, maxTokens: number, resourcePath: string, resourceName: string, functionName: string, parameters: ResourceFunctionCallParameter[], runId?: string): InferencePaymentVoucher;
|
|
121
155
|
}
|
|
122
156
|
//# 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;
|
|
1
|
+
{"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/resource/invoker.ts"],"names":[],"mappings":"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"}
|
package/dist/resource/invoker.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hashData, signData } from "../crypto/utils.js";
|
|
2
|
-
import { inferenceCharge, isInferenceFunction, isInferenceManifest, parseInferenceResult, parseMaxTokens } from "./inference.js";
|
|
2
|
+
import { estimateInputTokens, inferenceCharge, isInferenceFunction, isInferenceManifest, parseInferenceResult, parseMaxTokens } from "./inference.js";
|
|
3
|
+
import { settlePaidCall } from "./settlement.js";
|
|
3
4
|
/**
|
|
4
5
|
* Hash binding a voucher to one function call. Providers recompute it from the
|
|
5
6
|
* request they receive and compare it to `voucher.invocationHash`.
|
|
@@ -14,7 +15,11 @@ export function invocationHash(resourcePath, resourceName, functionName, paramet
|
|
|
14
15
|
*/
|
|
15
16
|
export function paymentVoucherPayload(voucher) {
|
|
16
17
|
const { requestId, invocationId, amount, recipientOrganizationId, expiresAt, invocationHash, publicKey } = voucher;
|
|
17
|
-
return { requestId, invocationId, amount, recipientOrganizationId, expiresAt, invocationHash, publicKey };
|
|
18
|
+
return { requestId, invocationId, amount, recipientOrganizationId, expiresAt, invocationHash, publicKey, ...runPayload(voucher.runId) };
|
|
19
|
+
}
|
|
20
|
+
/** `runId` is signed last, and only when set, so a voucher without one signs the same bytes as before it existed. */
|
|
21
|
+
function runPayload(runId) {
|
|
22
|
+
return runId === undefined ? {} : { runId };
|
|
18
23
|
}
|
|
19
24
|
/**
|
|
20
25
|
* The object `createInferenceVoucher` signs: every inference voucher field except `signature`.
|
|
@@ -22,7 +27,7 @@ export function paymentVoucherPayload(voucher) {
|
|
|
22
27
|
*/
|
|
23
28
|
export function inferenceVoucherPayload(voucher) {
|
|
24
29
|
const { kind, requestId, invocationId, maxAmount, inputCostMicroUsdPerMillionTokens, outputCostMicroUsdPerMillionTokens, maxTokens, recipientOrganizationId, expiresAt, invocationHash, publicKey } = voucher;
|
|
25
|
-
return { kind, requestId, invocationId, maxAmount, inputCostMicroUsdPerMillionTokens, outputCostMicroUsdPerMillionTokens, maxTokens, recipientOrganizationId, expiresAt, invocationHash, publicKey };
|
|
30
|
+
return { kind, requestId, invocationId, maxAmount, inputCostMicroUsdPerMillionTokens, outputCostMicroUsdPerMillionTokens, maxTokens, recipientOrganizationId, expiresAt, invocationHash, publicKey, ...runPayload(voucher.runId) };
|
|
26
31
|
}
|
|
27
32
|
export function isInferenceVoucher(voucher) {
|
|
28
33
|
return voucher.kind === 'inference';
|
|
@@ -68,17 +73,28 @@ export class CombinationResourceInvoker {
|
|
|
68
73
|
privateKey;
|
|
69
74
|
grantService;
|
|
70
75
|
inferenceCostLimitMicroUsd;
|
|
76
|
+
localSettlement;
|
|
71
77
|
/**
|
|
72
78
|
* Without a `grantService`, calls to restricted remote functions fail.
|
|
73
79
|
* `inferenceCostLimitMicroUsd` caps an inference voucher's `maxAmount`, and defaults to `costLimitMicroUsd`.
|
|
80
|
+
* Without `localSettlement`, a billed run can't call this node's own paid functions.
|
|
74
81
|
*/
|
|
75
|
-
constructor(resourceRepository, costLimitMicroUsd, publicKey, privateKey, grantService, inferenceCostLimitMicroUsd = costLimitMicroUsd) {
|
|
82
|
+
constructor(resourceRepository, costLimitMicroUsd, publicKey, privateKey, grantService, inferenceCostLimitMicroUsd = costLimitMicroUsd, localSettlement) {
|
|
76
83
|
this.resourceRepository = resourceRepository;
|
|
77
84
|
this.costLimitMicroUsd = costLimitMicroUsd;
|
|
78
85
|
this.publicKey = publicKey;
|
|
79
86
|
this.privateKey = privateKey;
|
|
80
87
|
this.grantService = grantService;
|
|
81
88
|
this.inferenceCostLimitMicroUsd = inferenceCostLimitMicroUsd;
|
|
89
|
+
this.localSettlement = localSettlement;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* An invoker for one billed run. Its paid calls, remote or to this node's own paid functions, carry
|
|
93
|
+
* the run's id, so the run's hold pays for them. The run's hold limits what they cost, in place of the
|
|
94
|
+
* cost limits.
|
|
95
|
+
*/
|
|
96
|
+
forRun(run) {
|
|
97
|
+
return { invoke: (resource, functionName, parameters) => this.invokeIn(resource, functionName, parameters, run) };
|
|
82
98
|
}
|
|
83
99
|
/**
|
|
84
100
|
* Invoke a function on a resource.
|
|
@@ -94,6 +110,9 @@ export class CombinationResourceInvoker {
|
|
|
94
110
|
* @returns The return value of the function
|
|
95
111
|
*/
|
|
96
112
|
async invoke(resource, functionName, parameters) {
|
|
113
|
+
return this.invokeIn(resource, functionName, parameters, undefined);
|
|
114
|
+
}
|
|
115
|
+
async invokeIn(resource, functionName, parameters, run) {
|
|
97
116
|
if (resource.metadata.baseUrl) {
|
|
98
117
|
let requestBody = {
|
|
99
118
|
resourcePath: resource.path,
|
|
@@ -139,20 +158,20 @@ export class CombinationResourceInvoker {
|
|
|
139
158
|
if (inferenceCharge(manifest, estimate.inputTokens, maxTokens) !== estimate.maxAmount) {
|
|
140
159
|
return { value: null, error: { message: `Failed to invoke ${resource.name}.${functionName}: the provider's estimate doesn't match its advertised rates` } };
|
|
141
160
|
}
|
|
142
|
-
if (estimate.maxAmount > this.inferenceCostLimitMicroUsd) {
|
|
161
|
+
if (!run && estimate.maxAmount > this.inferenceCostLimitMicroUsd) {
|
|
143
162
|
throw new Error(`Function ${functionName} may cost up to ${estimate.maxAmount} micro-USD, which exceeds the inference cost limit of ${this.inferenceCostLimitMicroUsd} micro-USD`);
|
|
144
163
|
}
|
|
145
|
-
requestBody.paymentVoucher = this.createInferenceVoucher(manifest, estimate.maxAmount, maxTokens, resource.path, resource.name, functionName, parameters);
|
|
164
|
+
requestBody.paymentVoucher = this.createInferenceVoucher(manifest, estimate.maxAmount, maxTokens, resource.path, resource.name, functionName, parameters, run?.runId);
|
|
146
165
|
}
|
|
147
166
|
else if (manifest) {
|
|
148
167
|
console.log(`Resource function ${resource.name}.${functionName} has a payment manifest, creating payment voucher...`);
|
|
149
168
|
if (isInferenceManifest(manifest)) {
|
|
150
169
|
return { value: null, error: { message: `Failed to invoke ${resource.name}.${functionName}: it has per-token pricing but isn't an inference function` } };
|
|
151
170
|
}
|
|
152
|
-
if (manifest.costMicroUsd > this.costLimitMicroUsd) {
|
|
171
|
+
if (!run && manifest.costMicroUsd > this.costLimitMicroUsd) {
|
|
153
172
|
throw new Error(`Function ${functionName} cost ${manifest.costMicroUsd} micro-USD, which exceeds the cost limit of ${this.costLimitMicroUsd} micro-USD`);
|
|
154
173
|
}
|
|
155
|
-
requestBody.paymentVoucher = this.createPaymentVoucher(manifest.recipientOrganizationId, manifest.costMicroUsd, resource.path, resource.name, functionName, parameters);
|
|
174
|
+
requestBody.paymentVoucher = this.createPaymentVoucher(manifest.recipientOrganizationId, manifest.costMicroUsd, resource.path, resource.name, functionName, parameters, run?.runId);
|
|
156
175
|
}
|
|
157
176
|
// The voucher is created once and reused on every attempt, so the operator's
|
|
158
177
|
// requestId/invocationId check prevents a retried call from being settled twice.
|
|
@@ -178,17 +197,57 @@ export class CombinationResourceInvoker {
|
|
|
178
197
|
if (!fn) {
|
|
179
198
|
return { value: null, error: { message: `Function ${functionName} not found in resource ${resource.name}` } };
|
|
180
199
|
}
|
|
181
|
-
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
if (!inferenceResult) {
|
|
185
|
-
return { value: null, error: { message: `Inference function ${functionName} must return { value, usage: { inputTokens, outputTokens } }` } };
|
|
186
|
-
}
|
|
187
|
-
return { value: inferenceResult.value, error: null, usage: inferenceResult.usage };
|
|
200
|
+
// A billed run pays for this node's own paid functions as a remote caller would.
|
|
201
|
+
if (run && fn.paymentManifest) {
|
|
202
|
+
return this.invokeLocalPaid(resource, fn, parameters, run);
|
|
188
203
|
}
|
|
189
|
-
return
|
|
204
|
+
return this.execLocal(fn, parameters);
|
|
190
205
|
}
|
|
191
206
|
}
|
|
207
|
+
async execLocal(fn, parameters) {
|
|
208
|
+
const result = await fn.exec(parameters);
|
|
209
|
+
if (isInferenceFunction(fn)) {
|
|
210
|
+
const inferenceResult = parseInferenceResult(result);
|
|
211
|
+
if (!inferenceResult) {
|
|
212
|
+
return { value: null, error: { message: `Inference function ${fn.name} must return { value, usage: { inputTokens, outputTokens } }` } };
|
|
213
|
+
}
|
|
214
|
+
return { value: inferenceResult.value, error: null, usage: inferenceResult.usage };
|
|
215
|
+
}
|
|
216
|
+
return { value: result, error: null };
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Calls one of this node's paid functions for a billed run: signs a voucher with the run's id that pays
|
|
220
|
+
* this node's organization, then authorizes, runs and settles it as `POST /v1/run/resource` would.
|
|
221
|
+
*/
|
|
222
|
+
async invokeLocalPaid(resource, fn, parameters, run) {
|
|
223
|
+
const failed = (reason) => ({ value: null, error: { message: `Failed to invoke ${resource.name}.${fn.name}: ${reason}` } });
|
|
224
|
+
const organizationId = this.localSettlement?.organizationId;
|
|
225
|
+
if (!this.localSettlement || !organizationId) {
|
|
226
|
+
return failed('this node is not enrolled in an organization that can be paid');
|
|
227
|
+
}
|
|
228
|
+
const manifest = fn.paymentManifest;
|
|
229
|
+
let voucher;
|
|
230
|
+
if (isInferenceFunction(fn) && isInferenceManifest(manifest)) {
|
|
231
|
+
const maxTokens = parseMaxTokens(parameters);
|
|
232
|
+
if (maxTokens === undefined) {
|
|
233
|
+
return failed('maxTokens must be a positive int32');
|
|
234
|
+
}
|
|
235
|
+
const inputTokens = await estimateInputTokens(fn, parameters);
|
|
236
|
+
if (inputTokens === undefined) {
|
|
237
|
+
return failed('failed to estimate input tokens');
|
|
238
|
+
}
|
|
239
|
+
const maxAmount = inferenceCharge(manifest, inputTokens, maxTokens);
|
|
240
|
+
voucher = this.createInferenceVoucher({ ...manifest, recipientOrganizationId: organizationId }, maxAmount, maxTokens, resource.path, resource.name, fn.name, parameters, run.runId);
|
|
241
|
+
}
|
|
242
|
+
else if (!isInferenceManifest(manifest)) {
|
|
243
|
+
voucher = this.createPaymentVoucher(organizationId, manifest.costMicroUsd, resource.path, resource.name, fn.name, parameters, run.runId);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
return failed('it has per-token pricing but isn\'t an inference function');
|
|
247
|
+
}
|
|
248
|
+
const result = await settlePaidCall(this.localSettlement.operatorClient, voucher, () => this.execLocal(fn, parameters), (error, message) => console.error(message, error));
|
|
249
|
+
return 'refused' in result ? failed(result.refused.error) : result;
|
|
250
|
+
}
|
|
192
251
|
/** Asks the provider what a call to a paid inference function will cost at most. */
|
|
193
252
|
async estimate(url, target, chain) {
|
|
194
253
|
let response;
|
|
@@ -213,15 +272,22 @@ export class CombinationResourceInvoker {
|
|
|
213
272
|
}
|
|
214
273
|
return { inputTokens: inputTokens, maxAmount: maxAmount };
|
|
215
274
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
275
|
+
/** With `runId`, the voucher is paid from that run's hold. */
|
|
276
|
+
createPaymentVoucher(recipientOrganizationId, amount, resourcePath, resourceName, functionName, parameters, runId) {
|
|
277
|
+
const unsigned = {
|
|
278
|
+
requestId: crypto.randomUUID(),
|
|
279
|
+
invocationId: crypto.randomUUID(),
|
|
280
|
+
amount,
|
|
281
|
+
recipientOrganizationId,
|
|
282
|
+
expiresAt: new Date(Date.now() + PAYMENT_VOUCHER_LIFETIME_MS).toISOString(),
|
|
283
|
+
invocationHash: invocationHash(resourcePath, resourceName, functionName, parameters),
|
|
284
|
+
publicKey: this.publicKey,
|
|
285
|
+
...runPayload(runId),
|
|
286
|
+
};
|
|
287
|
+
return { ...unsigned, signature: signData(paymentVoucherPayload(unsigned), this.privateKey) };
|
|
223
288
|
}
|
|
224
|
-
|
|
289
|
+
/** With `runId`, the voucher is paid from that run's hold. */
|
|
290
|
+
createInferenceVoucher(manifest, maxAmount, maxTokens, resourcePath, resourceName, functionName, parameters, runId) {
|
|
225
291
|
const unsigned = {
|
|
226
292
|
kind: 'inference',
|
|
227
293
|
requestId: crypto.randomUUID(),
|
|
@@ -234,6 +300,7 @@ export class CombinationResourceInvoker {
|
|
|
234
300
|
expiresAt: new Date(Date.now() + INFERENCE_VOUCHER_LIFETIME_MS).toISOString(),
|
|
235
301
|
invocationHash: invocationHash(resourcePath, resourceName, functionName, parameters),
|
|
236
302
|
publicKey: this.publicKey,
|
|
303
|
+
...runPayload(runId),
|
|
237
304
|
};
|
|
238
305
|
return { ...unsigned, signature: signData(inferenceVoucherPayload(unsigned), this.privateKey) };
|
|
239
306
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OperatorClient } from "../client/operatorClient.js";
|
|
2
|
+
import { type InferenceUsage } from "./inference.js";
|
|
3
|
+
import { type InferencePaymentVoucher, type PaymentVoucher } from "./invoker.js";
|
|
4
|
+
/** What a resource function call evaluates to, with an inference function's usage. */
|
|
5
|
+
export interface InvokeResult {
|
|
6
|
+
value: unknown;
|
|
7
|
+
error: {
|
|
8
|
+
message: string;
|
|
9
|
+
} | null;
|
|
10
|
+
usage?: InferenceUsage;
|
|
11
|
+
}
|
|
12
|
+
/** The operator refused to hold the voucher, so the call didn't run. */
|
|
13
|
+
export interface PaymentRefusal {
|
|
14
|
+
refused: {
|
|
15
|
+
status: number;
|
|
16
|
+
error: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Runs a paid call: holds the voucher's amount with the operator first, so a paid function never runs
|
|
21
|
+
* unpaid, then runs `call` and captures the voucher, or releases it for a failed or free call. Settlement is
|
|
22
|
+
* scheduled after returning, so it doesn't delay the caller, and failures go to `onSettleError`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function settlePaidCall(operatorClient: OperatorClient, voucher: PaymentVoucher | InferencePaymentVoucher, call: () => Promise<InvokeResult>, onSettleError: (error: unknown, message: string) => void): Promise<InvokeResult | PaymentRefusal>;
|
|
25
|
+
//# sourceMappingURL=settlement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement.d.ts","sourceRoot":"","sources":["../../src/resource/settlement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,KAAK,uBAAuB,EAAsB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAErG,sFAAsF;AACtF,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAYD;;;;GAIG;AACH,wBAAsB,cAAc,CAChC,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,cAAc,GAAG,uBAAuB,EACjD,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,EACjC,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GACzD,OAAO,CAAC,YAAY,GAAG,cAAc,CAAC,CAuCxC"}
|