stellarium-ts 0.16.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.
Files changed (46) hide show
  1. package/dist/client/operatorAuth.d.ts +19 -0
  2. package/dist/client/operatorAuth.d.ts.map +1 -0
  3. package/dist/client/operatorAuth.js +21 -0
  4. package/dist/client/operatorClient.d.ts +103 -31
  5. package/dist/client/operatorClient.d.ts.map +1 -1
  6. package/dist/client/operatorClient.js +107 -23
  7. package/dist/client/runTokens.d.ts +23 -0
  8. package/dist/client/runTokens.d.ts.map +1 -0
  9. package/dist/client/runTokens.js +34 -0
  10. package/dist/db/db.d.ts.map +1 -1
  11. package/dist/db/db.js +8 -5
  12. package/dist/index.d.ts +4 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +4 -0
  15. package/dist/resource/inference.d.ts +5 -3
  16. package/dist/resource/inference.d.ts.map +1 -1
  17. package/dist/resource/inference.js +17 -7
  18. package/dist/resource/invoker.d.ts +48 -14
  19. package/dist/resource/invoker.d.ts.map +1 -1
  20. package/dist/resource/invoker.js +108 -38
  21. package/dist/resource/repository.d.ts +13 -7
  22. package/dist/resource/repository.d.ts.map +1 -1
  23. package/dist/resource/repository.js +23 -13
  24. package/dist/resource/settlement.d.ts +25 -0
  25. package/dist/resource/settlement.d.ts.map +1 -0
  26. package/dist/resource/settlement.js +59 -0
  27. package/dist/routes.d.ts +16 -0
  28. package/dist/routes.d.ts.map +1 -1
  29. package/dist/routes.js +103 -76
  30. package/dist/server.d.ts +11 -6
  31. package/dist/server.d.ts.map +1 -1
  32. package/dist/server.js +32 -7
  33. package/dist/service.d.ts +18 -6
  34. package/dist/service.d.ts.map +1 -1
  35. package/dist/service.js +8 -3
  36. package/dist/tests/client/operatorClient.test.js +94 -36
  37. package/dist/tests/db/db.test.js +4 -4
  38. package/dist/tests/helpers.d.ts +4 -3
  39. package/dist/tests/helpers.d.ts.map +1 -1
  40. package/dist/tests/helpers.js +8 -6
  41. package/dist/tests/integration/network.test.js +69 -18
  42. package/dist/tests/resource/invoker.test.js +33 -9
  43. package/dist/tests/resource/repository.test.js +9 -9
  44. package/dist/tests/routes.test.js +165 -40
  45. package/dist/tests/server.test.js +15 -15
  46. package/package.json +3 -2
@@ -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";
@@ -6,11 +7,13 @@ export interface PaymentVoucher {
6
7
  requestId: string;
7
8
  invocationId: string;
8
9
  amount: number;
9
- recipientAddress: string;
10
+ recipientOrganizationId: string;
10
11
  signature: string;
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
@@ -22,14 +25,16 @@ export interface InferencePaymentVoucher {
22
25
  requestId: string;
23
26
  invocationId: string;
24
27
  maxAmount: number;
25
- inputCostMicroUsdcPerMillionTokens: number;
26
- outputCostMicroUsdcPerMillionTokens: number;
28
+ inputCostMicroUsdPerMillionTokens: number;
29
+ outputCostMicroUsdPerMillionTokens: number;
27
30
  maxTokens: number;
28
- recipientAddress: string;
31
+ recipientOrganizationId: string;
29
32
  signature: string;
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 {
@@ -50,24 +55,26 @@ export declare function paymentVoucherPayload(voucher: Omit<PaymentVoucher, "sig
50
55
  requestId: string;
51
56
  invocationId: string;
52
57
  amount: number;
53
- recipientAddress: string;
58
+ recipientOrganizationId: string;
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;
66
73
  maxAmount: number;
67
- inputCostMicroUsdcPerMillionTokens: number;
68
- outputCostMicroUsdcPerMillionTokens: number;
74
+ inputCostMicroUsdPerMillionTokens: number;
75
+ outputCostMicroUsdPerMillionTokens: number;
69
76
  maxTokens: number;
70
- recipientAddress: string;
77
+ recipientOrganizationId: string;
71
78
  expiresAt: string;
72
79
  invocationHash: string;
73
80
  publicKey: string;
@@ -82,18 +89,36 @@ 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
- private readonly costLimitMicroUsdc;
104
+ private readonly costLimitMicroUsd;
88
105
  private readonly publicKey;
89
106
  private readonly privateKey;
90
107
  private readonly grantService?;
91
- private readonly inferenceCostLimitMicroUsdc;
108
+ private readonly inferenceCostLimitMicroUsd;
109
+ private readonly localSettlement?;
92
110
  /**
93
111
  * Without a `grantService`, calls to restricted remote functions fail.
94
- * `inferenceCostLimitMicroUsdc` caps an inference voucher's `maxAmount`, and defaults to `costLimitMicroUsdc`.
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
- constructor(resourceRepository: ResourceRepository, costLimitMicroUsdc: number, publicKey: string, privateKey: string, grantService?: GrantService | undefined, inferenceCostLimitMicroUsdc?: number);
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
- createPaymentVoucher(recipientAddress: 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;
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;AAEzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAmB,KAAK,cAAc,EAAkF,MAAM,gBAAgB,CAAC;AACtJ,OAAO,EAAE,kBAAkB,EAAE,KAAK,kCAAkC,EAAmC,MAAM,iBAAiB,CAAC;AAE/H,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC,EAAE,MAAM,CAAC;IAC3C,mCAAmC,EAAE,MAAM,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC1B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,6BAA6B,EAAE,GAC5C,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC;;;;;;;;EAG/E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,WAAW,CAAC;;;;;;;;;;;;EAG1F;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,uBAAuB,GAAG,OAAO,IAAI,uBAAuB,CAExH;AAED,eAAO,MAAM,2BAA2B,QAAgB,CAAC;AACzD,qHAAqH;AACrH,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAE5D,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAC7C,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,wEAAwE;AACxE,eAAO,MAAM,0BAA0B,QAAS,CAAC;AACjD,gHAAgH;AAChH,eAAO,MAAM,2BAA2B,SAAU,CAAC;AA2BnD,qBAAa,0BAA2B,YAAW,eAAe;IAO1D,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAVhD;;;OAGG;IACH,YACqB,kBAAkB,EAAE,kBAAkB,EACtC,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,YAAY,YAAA,EAC3B,2BAA2B,GAAE,MAA2B,EACzE;IACJ;;;;;;;;;;;;OAYG;IACG,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,cAAc,CAAA;KAAE,CAAC,CAiGtL;IAED,oFAAoF;YACtE,QAAQ;IAuBtB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,6BAA6B,EAAE,GAAG,cAAc,CAO5L;IAED,sBAAsB,CAAC,QAAQ,EAAE,kCAAkC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,6BAA6B,EAAE,GAAG,uBAAuB,CAejP;CACJ"}
1
+ {"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/resource/invoker.ts"],"names":[],"mappings":"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"}
@@ -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`.
@@ -13,16 +14,20 @@ export function invocationHash(resourcePath, resourceName, functionName, paramet
13
14
  * Key order is part of the signed bytes.
14
15
  */
15
16
  export function paymentVoucherPayload(voucher) {
16
- const { requestId, invocationId, amount, recipientAddress, expiresAt, invocationHash, publicKey } = voucher;
17
- return { requestId, invocationId, amount, recipientAddress, expiresAt, invocationHash, publicKey };
17
+ const { requestId, invocationId, amount, recipientOrganizationId, expiresAt, invocationHash, publicKey } = voucher;
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`.
21
26
  * Key order is part of the signed bytes.
22
27
  */
23
28
  export function inferenceVoucherPayload(voucher) {
24
- const { kind, requestId, invocationId, maxAmount, inputCostMicroUsdcPerMillionTokens, outputCostMicroUsdcPerMillionTokens, maxTokens, recipientAddress, expiresAt, invocationHash, publicKey } = voucher;
25
- return { kind, requestId, invocationId, maxAmount, inputCostMicroUsdcPerMillionTokens, outputCostMicroUsdcPerMillionTokens, maxTokens, recipientAddress, expiresAt, invocationHash, publicKey };
29
+ const { kind, requestId, invocationId, maxAmount, inputCostMicroUsdPerMillionTokens, outputCostMicroUsdPerMillionTokens, maxTokens, recipientOrganizationId, expiresAt, invocationHash, publicKey } = voucher;
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';
@@ -63,22 +68,33 @@ async function fetchWithRetry(url, init, timeoutMs = EXTERNAL_INVOKE_TIMEOUT_MS)
63
68
  }
64
69
  export class CombinationResourceInvoker {
65
70
  resourceRepository;
66
- costLimitMicroUsdc;
71
+ costLimitMicroUsd;
67
72
  publicKey;
68
73
  privateKey;
69
74
  grantService;
70
- inferenceCostLimitMicroUsdc;
75
+ inferenceCostLimitMicroUsd;
76
+ localSettlement;
71
77
  /**
72
78
  * Without a `grantService`, calls to restricted remote functions fail.
73
- * `inferenceCostLimitMicroUsdc` caps an inference voucher's `maxAmount`, and defaults to `costLimitMicroUsdc`.
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, costLimitMicroUsdc, publicKey, privateKey, grantService, inferenceCostLimitMicroUsdc = costLimitMicroUsdc) {
82
+ constructor(resourceRepository, costLimitMicroUsd, publicKey, privateKey, grantService, inferenceCostLimitMicroUsd = costLimitMicroUsd, localSettlement) {
76
83
  this.resourceRepository = resourceRepository;
77
- this.costLimitMicroUsdc = costLimitMicroUsdc;
84
+ this.costLimitMicroUsd = costLimitMicroUsd;
78
85
  this.publicKey = publicKey;
79
86
  this.privateKey = privateKey;
80
87
  this.grantService = grantService;
81
- this.inferenceCostLimitMicroUsdc = inferenceCostLimitMicroUsdc;
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,
@@ -117,11 +136,14 @@ export class CombinationResourceInvoker {
117
136
  }
118
137
  const manifest = resourceFunction.paymentManifest;
119
138
  const inference = isInferenceFunction(resourceFunction);
139
+ if (manifest && !manifest.recipientOrganizationId) {
140
+ return { value: null, error: { message: `Failed to invoke ${resource.name}.${functionName}: its payment manifest names no recipient organization` } };
141
+ }
120
142
  if (manifest && inference) {
121
143
  console.log(`Resource function ${resource.name}.${functionName} is a paid inference function, creating payment voucher...`);
122
144
  // Peers' manifests aren't validated on receipt.
123
- if (!isInferenceManifest(manifest) || !Number.isSafeInteger(manifest.inputCostMicroUsdcPerMillionTokens) || manifest.inputCostMicroUsdcPerMillionTokens < 0
124
- || !Number.isSafeInteger(manifest.outputCostMicroUsdcPerMillionTokens) || manifest.outputCostMicroUsdcPerMillionTokens < 0) {
145
+ if (!isInferenceManifest(manifest) || !Number.isSafeInteger(manifest.inputCostMicroUsdPerMillionTokens) || manifest.inputCostMicroUsdPerMillionTokens < 0
146
+ || !Number.isSafeInteger(manifest.outputCostMicroUsdPerMillionTokens) || manifest.outputCostMicroUsdPerMillionTokens < 0) {
125
147
  return { value: null, error: { message: `Failed to invoke ${resource.name}.${functionName}: its payment manifest has no valid per-token pricing` } };
126
148
  }
127
149
  const maxTokens = parseMaxTokens(parameters);
@@ -136,20 +158,20 @@ export class CombinationResourceInvoker {
136
158
  if (inferenceCharge(manifest, estimate.inputTokens, maxTokens) !== estimate.maxAmount) {
137
159
  return { value: null, error: { message: `Failed to invoke ${resource.name}.${functionName}: the provider's estimate doesn't match its advertised rates` } };
138
160
  }
139
- if (estimate.maxAmount > this.inferenceCostLimitMicroUsdc) {
140
- throw new Error(`Function ${functionName} may cost up to ${estimate.maxAmount} micro-USDC, which exceeds the inference cost limit of ${this.inferenceCostLimitMicroUsdc} micro-USDC`);
161
+ if (!run && estimate.maxAmount > this.inferenceCostLimitMicroUsd) {
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`);
141
163
  }
142
- 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);
143
165
  }
144
166
  else if (manifest) {
145
167
  console.log(`Resource function ${resource.name}.${functionName} has a payment manifest, creating payment voucher...`);
146
168
  if (isInferenceManifest(manifest)) {
147
169
  return { value: null, error: { message: `Failed to invoke ${resource.name}.${functionName}: it has per-token pricing but isn't an inference function` } };
148
170
  }
149
- if (manifest.costMicroUsdc > this.costLimitMicroUsdc) {
150
- throw new Error(`Function ${functionName} cost ${manifest.costMicroUsdc} micro-USDC, which exceeds the cost limit of ${this.costLimitMicroUsdc} micro-USDC`);
171
+ if (!run && manifest.costMicroUsd > this.costLimitMicroUsd) {
172
+ throw new Error(`Function ${functionName} cost ${manifest.costMicroUsd} micro-USD, which exceeds the cost limit of ${this.costLimitMicroUsd} micro-USD`);
151
173
  }
152
- requestBody.paymentVoucher = this.createPaymentVoucher(manifest.recipientAddress, manifest.costMicroUsdc, resource.path, resource.name, functionName, parameters);
174
+ requestBody.paymentVoucher = this.createPaymentVoucher(manifest.recipientOrganizationId, manifest.costMicroUsd, resource.path, resource.name, functionName, parameters, run?.runId);
153
175
  }
154
176
  // The voucher is created once and reused on every attempt, so the operator's
155
177
  // requestId/invocationId check prevents a retried call from being settled twice.
@@ -175,16 +197,56 @@ export class CombinationResourceInvoker {
175
197
  if (!fn) {
176
198
  return { value: null, error: { message: `Function ${functionName} not found in resource ${resource.name}` } };
177
199
  }
178
- const result = await fn.exec(parameters);
179
- if (isInferenceFunction(fn)) {
180
- const inferenceResult = parseInferenceResult(result);
181
- if (!inferenceResult) {
182
- return { value: null, error: { message: `Inference function ${functionName} must return { value, usage: { inputTokens, outputTokens } }` } };
183
- }
184
- 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);
203
+ }
204
+ return this.execLocal(fn, parameters);
205
+ }
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');
185
238
  }
186
- return { value: result, error: null };
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');
187
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;
188
250
  }
189
251
  /** Asks the provider what a call to a paid inference function will cost at most. */
190
252
  async estimate(url, target, chain) {
@@ -210,27 +272,35 @@ export class CombinationResourceInvoker {
210
272
  }
211
273
  return { inputTokens: inputTokens, maxAmount: maxAmount };
212
274
  }
213
- createPaymentVoucher(recipientAddress, amount, resourcePath, resourceName, functionName, parameters) {
214
- const requestId = crypto.randomUUID();
215
- const invocationId = crypto.randomUUID();
216
- const expiresAt = new Date(Date.now() + PAYMENT_VOUCHER_LIFETIME_MS).toISOString();
217
- const hash = invocationHash(resourcePath, resourceName, functionName, parameters);
218
- const signature = signData(paymentVoucherPayload({ requestId, invocationId, amount, recipientAddress, expiresAt, invocationHash: hash, publicKey: this.publicKey }), this.privateKey);
219
- return { requestId, invocationId, amount, recipientAddress, signature, expiresAt, invocationHash: hash, publicKey: this.publicKey };
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) };
220
288
  }
221
- createInferenceVoucher(manifest, maxAmount, maxTokens, resourcePath, resourceName, functionName, parameters) {
289
+ /** With `runId`, the voucher is paid from that run's hold. */
290
+ createInferenceVoucher(manifest, maxAmount, maxTokens, resourcePath, resourceName, functionName, parameters, runId) {
222
291
  const unsigned = {
223
292
  kind: 'inference',
224
293
  requestId: crypto.randomUUID(),
225
294
  invocationId: crypto.randomUUID(),
226
295
  maxAmount,
227
- inputCostMicroUsdcPerMillionTokens: manifest.inputCostMicroUsdcPerMillionTokens,
228
- outputCostMicroUsdcPerMillionTokens: manifest.outputCostMicroUsdcPerMillionTokens,
296
+ inputCostMicroUsdPerMillionTokens: manifest.inputCostMicroUsdPerMillionTokens,
297
+ outputCostMicroUsdPerMillionTokens: manifest.outputCostMicroUsdPerMillionTokens,
229
298
  maxTokens,
230
- recipientAddress: manifest.recipientAddress,
299
+ recipientOrganizationId: manifest.recipientOrganizationId,
231
300
  expiresAt: new Date(Date.now() + INFERENCE_VOUCHER_LIFETIME_MS).toISOString(),
232
301
  invocationHash: invocationHash(resourcePath, resourceName, functionName, parameters),
233
302
  publicKey: this.publicKey,
303
+ ...runPayload(runId),
234
304
  };
235
305
  return { ...unsigned, signature: signData(inferenceVoucherPayload(unsigned), this.privateKey) };
236
306
  }
@@ -1,18 +1,21 @@
1
1
  import { Resource, ResourceFunction, ResourceFunctionCallParameter, ResourceFunctionParameter } from "requestscript";
2
2
  import { Database } from "sqlite";
3
3
  import type { StoredPeer } from "../peer/repository.js";
4
- /** A flat price per call. */
4
+ /**
5
+ * A flat price per call. `recipientOrganizationId` is filled in by the hosting node when it advertises
6
+ * the function, from the organization it is enrolled in; resource authors leave it out.
7
+ */
5
8
  export interface StellariumFixedPaymentManifest {
6
9
  id?: number;
7
- costMicroUsdc: number;
8
- recipientAddress: string;
10
+ costMicroUsd: number;
11
+ recipientOrganizationId?: string;
9
12
  }
10
13
  /** Per-token pricing for an inference function. Either rate may be 0. */
11
14
  export interface StellariumInferencePaymentManifest {
12
15
  id?: number;
13
- inputCostMicroUsdcPerMillionTokens: number;
14
- outputCostMicroUsdcPerMillionTokens: number;
15
- recipientAddress: string;
16
+ inputCostMicroUsdPerMillionTokens: number;
17
+ outputCostMicroUsdPerMillionTokens: number;
18
+ recipientOrganizationId?: string;
16
19
  }
17
20
  export type StellariumResourceFunctionPaymentManifest = StellariumFixedPaymentManifest | StellariumInferencePaymentManifest;
18
21
  /** Fixed functions return one value. Inference functions run AI inference and are priced per token. */
@@ -61,8 +64,10 @@ export declare class ResourceRepository {
61
64
  private readonly db;
62
65
  private resources;
63
66
  private readonly baseUrl;
67
+ private readonly organizationId?;
64
68
  private writes;
65
- constructor(db: Database, resources?: StellariumResource[], baseUrl?: string);
69
+ /** `organizationId` is the operator organization this node is enrolled in, which is paid for its functions. */
70
+ constructor(db: Database, resources?: StellariumResource[], baseUrl?: string, organizationId?: string | undefined);
66
71
  private serialize;
67
72
  private transaction;
68
73
  private isInternal;
@@ -84,6 +89,7 @@ export declare class ResourceRepository {
84
89
  private deleteFunctions;
85
90
  getInternalResource(path: string, name: string): Promise<StellariumResource | undefined>;
86
91
  getResource(key: string): Promise<Resource | undefined>;
92
+ /** This node's resources, with its base URL and its organization as the recipient of every paid function. */
87
93
  getInternalResources(): Promise<StellariumResource[]>;
88
94
  /** Learned resources in insertion order. A negative `limit` means no limit. */
89
95
  getExternalResources(offset?: number, limit?: number): Promise<StellariumResource[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/resource/repository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/resource/repository.ts"],"names":[],"mappings":"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"}
@@ -24,12 +24,15 @@ export class ResourceRepository {
24
24
  db;
25
25
  resources;
26
26
  baseUrl;
27
+ organizationId;
27
28
  // The connection is shared, so transactions are serialized to keep them from nesting.
28
29
  writes = Promise.resolve();
29
- constructor(db, resources = [], baseUrl = '') {
30
+ /** `organizationId` is the operator organization this node is enrolled in, which is paid for its functions. */
31
+ constructor(db, resources = [], baseUrl = '', organizationId) {
30
32
  this.db = db;
31
33
  this.resources = resources;
32
34
  this.baseUrl = baseUrl;
35
+ this.organizationId = organizationId;
33
36
  }
34
37
  serialize(work) {
35
38
  const run = this.writes.then(work, work);
@@ -123,12 +126,12 @@ export class ResourceRepository {
123
126
  const manifest = fn.paymentManifest;
124
127
  if (manifest) {
125
128
  const inference = isInferenceManifest(manifest);
126
- await this.db.run('INSERT INTO resource_function_payment_manifest (resource_function_id, cost_micro_usdc, input_cost_micro_usdc_per_million_tokens, output_cost_micro_usdc_per_million_tokens, recipient_address, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)', [
129
+ await this.db.run('INSERT INTO resource_function_payment_manifest (resource_function_id, cost_micro_usd, input_cost_micro_usd_per_million_tokens, output_cost_micro_usd_per_million_tokens, recipient_organization_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)', [
127
130
  functionId,
128
- inference ? null : manifest.costMicroUsdc,
129
- inference ? manifest.inputCostMicroUsdcPerMillionTokens : null,
130
- inference ? manifest.outputCostMicroUsdcPerMillionTokens : null,
131
- manifest.recipientAddress,
131
+ inference ? null : manifest.costMicroUsd,
132
+ inference ? manifest.inputCostMicroUsdPerMillionTokens : null,
133
+ inference ? manifest.outputCostMicroUsdPerMillionTokens : null,
134
+ manifest.recipientOrganizationId ?? null,
132
135
  createdAt,
133
136
  createdAt,
134
137
  ]);
@@ -167,8 +170,15 @@ export class ResourceRepository {
167
170
  }
168
171
  };
169
172
  }
173
+ /** This node's resources, with its base URL and its organization as the recipient of every paid function. */
170
174
  async getInternalResources() {
171
- return this.resources.map(r => ({ ...r, baseUrl: this.baseUrl }));
175
+ return this.resources.map(r => ({
176
+ ...r,
177
+ baseUrl: this.baseUrl,
178
+ functions: r.functions.map((fn) => fn.paymentManifest
179
+ ? { ...fn, paymentManifest: { ...fn.paymentManifest, recipientOrganizationId: this.organizationId } }
180
+ : fn),
181
+ }));
172
182
  }
173
183
  /** Learned resources in insertion order. A negative `limit` means no limit. */
174
184
  async getExternalResources(offset = 0, limit = -1) {
@@ -231,18 +241,18 @@ export class ResourceRepository {
231
241
  if (!result) {
232
242
  return undefined;
233
243
  }
234
- if (result.cost_micro_usdc === null) {
244
+ if (result.cost_micro_usd === null) {
235
245
  return {
236
246
  id: result.id,
237
- inputCostMicroUsdcPerMillionTokens: result.input_cost_micro_usdc_per_million_tokens,
238
- outputCostMicroUsdcPerMillionTokens: result.output_cost_micro_usdc_per_million_tokens,
239
- recipientAddress: result.recipient_address,
247
+ inputCostMicroUsdPerMillionTokens: result.input_cost_micro_usd_per_million_tokens,
248
+ outputCostMicroUsdPerMillionTokens: result.output_cost_micro_usd_per_million_tokens,
249
+ recipientOrganizationId: result.recipient_organization_id ?? undefined,
240
250
  };
241
251
  }
242
252
  return {
243
253
  id: result.id,
244
- costMicroUsdc: result.cost_micro_usdc,
245
- recipientAddress: result.recipient_address,
254
+ costMicroUsd: result.cost_micro_usd,
255
+ recipientOrganizationId: result.recipient_organization_id ?? undefined,
246
256
  };
247
257
  }
248
258
  /**
@@ -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"}
@@ -0,0 +1,59 @@
1
+ import { inferenceCharge } from "./inference.js";
2
+ import { isInferenceVoucher } from "./invoker.js";
3
+ /** What the operator will capture for `usage`: its charge at the voucher's rates, capped at `maxAmount`. */
4
+ function cappedInferenceCharge(voucher, usage) {
5
+ try {
6
+ return Math.min(inferenceCharge(voucher, usage.inputTokens, usage.outputTokens), voucher.maxAmount);
7
+ }
8
+ catch {
9
+ // The charge isn't a safe integer, so it is over any maxAmount.
10
+ return voucher.maxAmount;
11
+ }
12
+ }
13
+ /**
14
+ * Runs a paid call: holds the voucher's amount with the operator first, so a paid function never runs
15
+ * unpaid, then runs `call` and captures the voucher, or releases it for a failed or free call. Settlement is
16
+ * scheduled after returning, so it doesn't delay the caller, and failures go to `onSettleError`.
17
+ */
18
+ export async function settlePaidCall(operatorClient, voucher, call, onSettleError) {
19
+ const authorization = await operatorClient.authorize(voucher);
20
+ if (!authorization.ok) {
21
+ return { refused: { status: authorization.status, error: authorization.error } };
22
+ }
23
+ let capture;
24
+ const settle = () => setTimeout(async () => {
25
+ try {
26
+ if (capture) {
27
+ await operatorClient.capture(capture);
28
+ }
29
+ else {
30
+ await operatorClient.release(voucher);
31
+ }
32
+ }
33
+ catch (error) {
34
+ onSettleError(error, capture ? 'Failed to capture payment' : 'Failed to release payment');
35
+ }
36
+ }, 0);
37
+ let result;
38
+ try {
39
+ result = await call();
40
+ }
41
+ catch (error) {
42
+ settle();
43
+ throw error;
44
+ }
45
+ if (!result.error && !isInferenceVoucher(voucher)) {
46
+ capture = { voucher };
47
+ }
48
+ else if (!result.error && result.usage && isInferenceVoucher(voucher)) {
49
+ // The function may report more output than it was allowed; the caller only signed for maxTokens.
50
+ const usage = { inputTokens: result.usage.inputTokens, outputTokens: Math.min(result.usage.outputTokens, voucher.maxTokens) };
51
+ result.usage = usage;
52
+ // A free call has nothing to charge, so its hold is released instead.
53
+ if (cappedInferenceCharge(voucher, usage) > 0) {
54
+ capture = { voucher, usage };
55
+ }
56
+ }
57
+ settle();
58
+ return result;
59
+ }