@net-mesh/sdk 0.19.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/README.md +1684 -0
- package/dist/_internal.d.ts +25 -0
- package/dist/_internal.js +60 -0
- package/dist/capabilities.d.ts +271 -0
- package/dist/capabilities.js +186 -0
- package/dist/capability-enhancements.d.ts +574 -0
- package/dist/capability-enhancements.js +1324 -0
- package/dist/capability-schema.d.ts +112 -0
- package/dist/capability-schema.js +317 -0
- package/dist/channel.d.ts +56 -0
- package/dist/channel.js +95 -0
- package/dist/compute.d.ts +546 -0
- package/dist/compute.js +741 -0
- package/dist/cortex.d.ts +236 -0
- package/dist/cortex.js +584 -0
- package/dist/deck.d.ts +342 -0
- package/dist/deck.js +717 -0
- package/dist/groups.d.ts +208 -0
- package/dist/groups.js +431 -0
- package/dist/identity.d.ts +149 -0
- package/dist/identity.js +264 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +147 -0
- package/dist/mesh.d.ts +369 -0
- package/dist/mesh.js +433 -0
- package/dist/meshdb.d.ts +87 -0
- package/dist/meshdb.js +111 -0
- package/dist/meshos.d.ts +277 -0
- package/dist/meshos.js +359 -0
- package/dist/node.d.ts +120 -0
- package/dist/node.js +246 -0
- package/dist/redis-dedup.d.ts +48 -0
- package/dist/redis-dedup.js +52 -0
- package/dist/stream.d.ts +47 -0
- package/dist/stream.js +118 -0
- package/dist/subnets.d.ts +75 -0
- package/dist/subnets.js +54 -0
- package/dist/types.d.ts +102 -0
- package/dist/types.js +5 -0
- package/package.json +43 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-internal handles used by sibling SDK modules to share
|
|
3
|
+
* the underlying NAPI objects without exposing them on the
|
|
4
|
+
* public class surface.
|
|
5
|
+
*
|
|
6
|
+
* Previously this was a leading-underscore method (`_napiRuntime`,
|
|
7
|
+
* `_napiNetMesh`) on each wrapper class. That left a runtime-
|
|
8
|
+
* discoverable escape hatch: a consumer casting the class instance
|
|
9
|
+
* to `any` could call the method and reach the unstable NAPI
|
|
10
|
+
* surface, bypassing the wrapper's typed error / lifecycle
|
|
11
|
+
* boundaries. `stripInternal: true` hid the method from emitted
|
|
12
|
+
* `.d.ts` but the method still existed on every instance.
|
|
13
|
+
*
|
|
14
|
+
* This file swaps that for a WeakMap-per-handle so the napi
|
|
15
|
+
* pointer is keyed off the wrapper instance but is NOT a property
|
|
16
|
+
* of it. Only code that imports these helpers directly can reach
|
|
17
|
+
* the native pointer; the helpers are `@internal` and never
|
|
18
|
+
* re-exported from `index.ts`, so a consumer would have to deep-
|
|
19
|
+
* import this file deliberately — the usual "you're breaking the
|
|
20
|
+
* seal" ergonomics.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Module-internal handles used by sibling SDK modules to share
|
|
4
|
+
* the underlying NAPI objects without exposing them on the
|
|
5
|
+
* public class surface.
|
|
6
|
+
*
|
|
7
|
+
* Previously this was a leading-underscore method (`_napiRuntime`,
|
|
8
|
+
* `_napiNetMesh`) on each wrapper class. That left a runtime-
|
|
9
|
+
* discoverable escape hatch: a consumer casting the class instance
|
|
10
|
+
* to `any` could call the method and reach the unstable NAPI
|
|
11
|
+
* surface, bypassing the wrapper's typed error / lifecycle
|
|
12
|
+
* boundaries. `stripInternal: true` hid the method from emitted
|
|
13
|
+
* `.d.ts` but the method still existed on every instance.
|
|
14
|
+
*
|
|
15
|
+
* This file swaps that for a WeakMap-per-handle so the napi
|
|
16
|
+
* pointer is keyed off the wrapper instance but is NOT a property
|
|
17
|
+
* of it. Only code that imports these helpers directly can reach
|
|
18
|
+
* the native pointer; the helpers are `@internal` and never
|
|
19
|
+
* re-exported from `index.ts`, so a consumer would have to deep-
|
|
20
|
+
* import this file deliberately — the usual "you're breaking the
|
|
21
|
+
* seal" ergonomics.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
* @packageDocumentation
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.setNapiRuntime = setNapiRuntime;
|
|
28
|
+
exports.getNapiRuntime = getNapiRuntime;
|
|
29
|
+
exports.setNapiMesh = setNapiMesh;
|
|
30
|
+
exports.getNapiMesh = getNapiMesh;
|
|
31
|
+
// `WeakMap<object, …>` avoids pinning the wrapper in memory — when
|
|
32
|
+
// a DaemonRuntime is garbage-collected the entry evicts automatically.
|
|
33
|
+
const napiRuntimes = new WeakMap();
|
|
34
|
+
const napiMeshes = new WeakMap();
|
|
35
|
+
/** @internal */
|
|
36
|
+
function setNapiRuntime(host, napi) {
|
|
37
|
+
napiRuntimes.set(host, napi);
|
|
38
|
+
}
|
|
39
|
+
/** @internal */
|
|
40
|
+
function getNapiRuntime(host) {
|
|
41
|
+
const r = napiRuntimes.get(host);
|
|
42
|
+
if (!r) {
|
|
43
|
+
throw new Error('internal: no NAPI runtime registered for this DaemonRuntime — ' +
|
|
44
|
+
'constructor may not have run');
|
|
45
|
+
}
|
|
46
|
+
return r;
|
|
47
|
+
}
|
|
48
|
+
/** @internal */
|
|
49
|
+
function setNapiMesh(host, napi) {
|
|
50
|
+
napiMeshes.set(host, napi);
|
|
51
|
+
}
|
|
52
|
+
/** @internal */
|
|
53
|
+
function getNapiMesh(host) {
|
|
54
|
+
const r = napiMeshes.get(host);
|
|
55
|
+
if (!r) {
|
|
56
|
+
throw new Error('internal: no NAPI mesh registered for this MeshNode — ' +
|
|
57
|
+
'constructor may not have run');
|
|
58
|
+
}
|
|
59
|
+
return r;
|
|
60
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability declarations — hardware / software / models / tools /
|
|
3
|
+
* tags / resource limits — and the filters that query them.
|
|
4
|
+
*
|
|
5
|
+
* Construct a {@link CapabilitySet} from whatever your node actually
|
|
6
|
+
* runs, hand it to {@link MeshNode.announceCapabilities}, and the
|
|
7
|
+
* mesh pushes it to every directly-connected peer. Peers keep the
|
|
8
|
+
* latest announcement from each node in their local capability
|
|
9
|
+
* index; {@link MeshNode.findNodes} queries that index.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { MeshNode } from '@net-mesh/sdk';
|
|
14
|
+
*
|
|
15
|
+
* await node.announceCapabilities({
|
|
16
|
+
* hardware: {
|
|
17
|
+
* cpuCores: 16,
|
|
18
|
+
* memoryGb: 64,
|
|
19
|
+
* gpu: { vendor: 'nvidia', model: 'RTX 4090', vramGb: 24 },
|
|
20
|
+
* },
|
|
21
|
+
* tags: ['gpu', 'inference'],
|
|
22
|
+
* models: [{ modelId: 'llama-3.1-70b', family: 'llama' }],
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const peers = node.findNodes({ requireTags: ['gpu'], minVramMb: 16_384 });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Multi-hop propagation is deferred; today peers more than one hop
|
|
29
|
+
* away are not visible.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* GPU vendor. Case-insensitive on input (`'NVIDIA'`, `'nvidia'`,
|
|
33
|
+
* `'Nvidia'` all normalize to `'nvidia'`). Unknown / misspelled
|
|
34
|
+
* vendors collapse to `'unknown'`.
|
|
35
|
+
*/
|
|
36
|
+
export type GpuVendor = 'nvidia' | 'amd' | 'intel' | 'apple' | 'qualcomm' | 'unknown';
|
|
37
|
+
export interface GpuInfo {
|
|
38
|
+
vendor?: GpuVendor;
|
|
39
|
+
model: string;
|
|
40
|
+
vramGb: number;
|
|
41
|
+
computeUnits?: number;
|
|
42
|
+
tensorCores?: number;
|
|
43
|
+
/** FP16 TFLOPS × 10 (integer) — e.g. 825 for 82.5 TFLOPS. */
|
|
44
|
+
fp16TflopsX10?: number;
|
|
45
|
+
}
|
|
46
|
+
export type AcceleratorKind = 'tpu' | 'npu' | 'fpga' | 'asic' | 'dsp' | 'unknown';
|
|
47
|
+
export interface Accelerator {
|
|
48
|
+
kind: AcceleratorKind;
|
|
49
|
+
model: string;
|
|
50
|
+
memoryGb?: number;
|
|
51
|
+
/** TOPS × 10 (integer). */
|
|
52
|
+
topsX10?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface Hardware {
|
|
55
|
+
cpuCores?: number;
|
|
56
|
+
cpuThreads?: number;
|
|
57
|
+
memoryGb?: number;
|
|
58
|
+
gpu?: GpuInfo;
|
|
59
|
+
additionalGpus?: GpuInfo[];
|
|
60
|
+
/** Storage in GB. BigInt to carry multi-TB values without loss. */
|
|
61
|
+
storageGb?: bigint;
|
|
62
|
+
networkGbps?: number;
|
|
63
|
+
accelerators?: Accelerator[];
|
|
64
|
+
}
|
|
65
|
+
/** `[runtime_name, version]` pair used by runtimes/frameworks/drivers. */
|
|
66
|
+
export type SoftwarePair = [string, string];
|
|
67
|
+
export interface Software {
|
|
68
|
+
os?: string;
|
|
69
|
+
osVersion?: string;
|
|
70
|
+
runtimes?: SoftwarePair[];
|
|
71
|
+
frameworks?: SoftwarePair[];
|
|
72
|
+
cudaVersion?: string;
|
|
73
|
+
drivers?: SoftwarePair[];
|
|
74
|
+
}
|
|
75
|
+
export type Modality = 'text' | 'image' | 'audio' | 'video' | 'code' | 'embedding' | 'tool-use';
|
|
76
|
+
export interface ModelCapability {
|
|
77
|
+
modelId: string;
|
|
78
|
+
family?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Parameter count, billions × 10 (70 B ⇒ 700). Integer-encoded to
|
|
81
|
+
* avoid float precision loss; the core uses the same layout.
|
|
82
|
+
*/
|
|
83
|
+
parametersBX10?: number;
|
|
84
|
+
contextLength?: number;
|
|
85
|
+
quantization?: string;
|
|
86
|
+
modalities?: Modality[];
|
|
87
|
+
tokensPerSec?: number;
|
|
88
|
+
loaded?: boolean;
|
|
89
|
+
}
|
|
90
|
+
export interface ToolCapability {
|
|
91
|
+
toolId: string;
|
|
92
|
+
name?: string;
|
|
93
|
+
version?: string;
|
|
94
|
+
/** JSON-Schema string. */
|
|
95
|
+
inputSchema?: string;
|
|
96
|
+
/** JSON-Schema string. */
|
|
97
|
+
outputSchema?: string;
|
|
98
|
+
requires?: string[];
|
|
99
|
+
estimatedTimeMs?: number;
|
|
100
|
+
stateless?: boolean;
|
|
101
|
+
}
|
|
102
|
+
export interface CapabilityLimits {
|
|
103
|
+
maxConcurrentRequests?: number;
|
|
104
|
+
maxTokensPerRequest?: number;
|
|
105
|
+
rateLimitRpm?: number;
|
|
106
|
+
maxBatchSize?: number;
|
|
107
|
+
maxInputBytes?: number;
|
|
108
|
+
maxOutputBytes?: number;
|
|
109
|
+
}
|
|
110
|
+
export interface CapabilitySet {
|
|
111
|
+
hardware?: Hardware;
|
|
112
|
+
software?: Software;
|
|
113
|
+
models?: ModelCapability[];
|
|
114
|
+
tools?: ToolCapability[];
|
|
115
|
+
tags?: string[];
|
|
116
|
+
limits?: CapabilityLimits;
|
|
117
|
+
}
|
|
118
|
+
export interface CapabilityFilter {
|
|
119
|
+
requireTags?: string[];
|
|
120
|
+
requireModels?: string[];
|
|
121
|
+
requireTools?: string[];
|
|
122
|
+
minMemoryMb?: number;
|
|
123
|
+
requireGpu?: boolean;
|
|
124
|
+
gpuVendor?: GpuVendor;
|
|
125
|
+
minVramMb?: number;
|
|
126
|
+
minContextLength?: number;
|
|
127
|
+
requireModalities?: Modality[];
|
|
128
|
+
}
|
|
129
|
+
interface NapiGpuInfo {
|
|
130
|
+
vendor?: string;
|
|
131
|
+
model: string;
|
|
132
|
+
vramGb: number;
|
|
133
|
+
computeUnits?: number;
|
|
134
|
+
tensorCores?: number;
|
|
135
|
+
fp16TflopsX10?: number;
|
|
136
|
+
}
|
|
137
|
+
interface NapiAccelerator {
|
|
138
|
+
kind: string;
|
|
139
|
+
model: string;
|
|
140
|
+
memoryGb?: number;
|
|
141
|
+
topsX10?: number;
|
|
142
|
+
}
|
|
143
|
+
interface NapiHardware {
|
|
144
|
+
cpuCores?: number;
|
|
145
|
+
cpuThreads?: number;
|
|
146
|
+
memoryGb?: number;
|
|
147
|
+
gpu?: NapiGpuInfo;
|
|
148
|
+
additionalGpus?: NapiGpuInfo[];
|
|
149
|
+
storageGb?: bigint;
|
|
150
|
+
networkGbps?: number;
|
|
151
|
+
accelerators?: NapiAccelerator[];
|
|
152
|
+
}
|
|
153
|
+
interface NapiSoftware {
|
|
154
|
+
os?: string;
|
|
155
|
+
osVersion?: string;
|
|
156
|
+
runtimes?: string[][];
|
|
157
|
+
frameworks?: string[][];
|
|
158
|
+
cudaVersion?: string;
|
|
159
|
+
drivers?: string[][];
|
|
160
|
+
}
|
|
161
|
+
interface NapiModel {
|
|
162
|
+
modelId: string;
|
|
163
|
+
family?: string;
|
|
164
|
+
parametersBX10?: number;
|
|
165
|
+
contextLength?: number;
|
|
166
|
+
quantization?: string;
|
|
167
|
+
modalities?: string[];
|
|
168
|
+
tokensPerSec?: number;
|
|
169
|
+
loaded?: boolean;
|
|
170
|
+
}
|
|
171
|
+
interface NapiTool {
|
|
172
|
+
toolId: string;
|
|
173
|
+
name?: string;
|
|
174
|
+
version?: string;
|
|
175
|
+
inputSchema?: string;
|
|
176
|
+
outputSchema?: string;
|
|
177
|
+
requires?: string[];
|
|
178
|
+
estimatedTimeMs?: number;
|
|
179
|
+
stateless?: boolean;
|
|
180
|
+
}
|
|
181
|
+
interface NapiLimits {
|
|
182
|
+
maxConcurrentRequests?: number;
|
|
183
|
+
maxTokensPerRequest?: number;
|
|
184
|
+
rateLimitRpm?: number;
|
|
185
|
+
maxBatchSize?: number;
|
|
186
|
+
maxInputBytes?: number;
|
|
187
|
+
maxOutputBytes?: number;
|
|
188
|
+
}
|
|
189
|
+
/** Shape that napi-rs expects for `announceCapabilities`. */
|
|
190
|
+
export interface NapiCapabilitySet {
|
|
191
|
+
hardware?: NapiHardware;
|
|
192
|
+
software?: NapiSoftware;
|
|
193
|
+
models?: NapiModel[];
|
|
194
|
+
tools?: NapiTool[];
|
|
195
|
+
tags?: string[];
|
|
196
|
+
limits?: NapiLimits;
|
|
197
|
+
}
|
|
198
|
+
/** Shape that napi-rs expects for `findNodes`. */
|
|
199
|
+
export interface NapiCapabilityFilter {
|
|
200
|
+
requireTags?: string[];
|
|
201
|
+
requireModels?: string[];
|
|
202
|
+
requireTools?: string[];
|
|
203
|
+
minMemoryMb?: number;
|
|
204
|
+
requireGpu?: boolean;
|
|
205
|
+
gpuVendor?: string;
|
|
206
|
+
minVramMb?: number;
|
|
207
|
+
minContextLength?: number;
|
|
208
|
+
requireModalities?: string[];
|
|
209
|
+
}
|
|
210
|
+
export declare function capabilitySetToNapi(caps: CapabilitySet): NapiCapabilitySet;
|
|
211
|
+
export declare function capabilityFilterToNapi(f: CapabilityFilter): NapiCapabilityFilter;
|
|
212
|
+
/**
|
|
213
|
+
* Caller's intent for narrowing peer discovery by reserved
|
|
214
|
+
* `scope:*` tags. See {@link MeshNode.findNodesScoped}.
|
|
215
|
+
*
|
|
216
|
+
* Tag-based scope is a query-time concern — the wire format is
|
|
217
|
+
* untouched. Untagged peers resolve to `Global` and stay visible
|
|
218
|
+
* under most filters by design (matches the v1-permissive
|
|
219
|
+
* default). Peers tagged `scope:subnet-local` only show up under
|
|
220
|
+
* `sameSubnet`.
|
|
221
|
+
*/
|
|
222
|
+
export type ScopeFilter = {
|
|
223
|
+
kind: 'any';
|
|
224
|
+
} | {
|
|
225
|
+
kind: 'globalOnly';
|
|
226
|
+
} | {
|
|
227
|
+
kind: 'sameSubnet';
|
|
228
|
+
} | {
|
|
229
|
+
kind: 'tenant';
|
|
230
|
+
tenant: string;
|
|
231
|
+
} | {
|
|
232
|
+
kind: 'tenants';
|
|
233
|
+
tenants: string[];
|
|
234
|
+
} | {
|
|
235
|
+
kind: 'region';
|
|
236
|
+
region: string;
|
|
237
|
+
} | {
|
|
238
|
+
kind: 'regions';
|
|
239
|
+
regions: string[];
|
|
240
|
+
};
|
|
241
|
+
/** Shape that napi-rs expects for `findNodesScoped`. */
|
|
242
|
+
export interface NapiScopeFilter {
|
|
243
|
+
kind: string;
|
|
244
|
+
tenant?: string;
|
|
245
|
+
tenants?: string[];
|
|
246
|
+
region?: string;
|
|
247
|
+
regions?: string[];
|
|
248
|
+
}
|
|
249
|
+
export declare function scopeFilterToNapi(s: ScopeFilter): NapiScopeFilter;
|
|
250
|
+
/** Reserved tag prefix for tenant-scoped announcements. */
|
|
251
|
+
export declare const SCOPE_TENANT_PREFIX = "scope:tenant:";
|
|
252
|
+
/** Reserved tag prefix for region-scoped announcements. */
|
|
253
|
+
export declare const SCOPE_REGION_PREFIX = "scope:region:";
|
|
254
|
+
/** Reserved tag marking an announcement subnet-local. */
|
|
255
|
+
export declare const SCOPE_SUBNET_LOCAL = "scope:subnet-local";
|
|
256
|
+
/**
|
|
257
|
+
* Append a `scope:tenant:<id>` tag to a tag list. Idempotent —
|
|
258
|
+
* safe to call repeatedly with the same id. Empty `tenantId` is a
|
|
259
|
+
* no-op.
|
|
260
|
+
*/
|
|
261
|
+
export declare function withTenantScope(tags: string[] | undefined, tenantId: string): string[];
|
|
262
|
+
/** Append a `scope:region:<name>` tag to a tag list. Idempotent. */
|
|
263
|
+
export declare function withRegionScope(tags: string[] | undefined, region: string): string[];
|
|
264
|
+
/**
|
|
265
|
+
* Append the `scope:subnet-local` tag to a tag list. Idempotent.
|
|
266
|
+
* Strictest form wins on the resolver — when this tag is present,
|
|
267
|
+
* tenant/region tags on the same set are ignored by
|
|
268
|
+
* `CapabilityScope`.
|
|
269
|
+
*/
|
|
270
|
+
export declare function withSubnetLocalScope(tags: string[] | undefined): string[];
|
|
271
|
+
export {};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Capability declarations — hardware / software / models / tools /
|
|
4
|
+
* tags / resource limits — and the filters that query them.
|
|
5
|
+
*
|
|
6
|
+
* Construct a {@link CapabilitySet} from whatever your node actually
|
|
7
|
+
* runs, hand it to {@link MeshNode.announceCapabilities}, and the
|
|
8
|
+
* mesh pushes it to every directly-connected peer. Peers keep the
|
|
9
|
+
* latest announcement from each node in their local capability
|
|
10
|
+
* index; {@link MeshNode.findNodes} queries that index.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { MeshNode } from '@net-mesh/sdk';
|
|
15
|
+
*
|
|
16
|
+
* await node.announceCapabilities({
|
|
17
|
+
* hardware: {
|
|
18
|
+
* cpuCores: 16,
|
|
19
|
+
* memoryGb: 64,
|
|
20
|
+
* gpu: { vendor: 'nvidia', model: 'RTX 4090', vramGb: 24 },
|
|
21
|
+
* },
|
|
22
|
+
* tags: ['gpu', 'inference'],
|
|
23
|
+
* models: [{ modelId: 'llama-3.1-70b', family: 'llama' }],
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const peers = node.findNodes({ requireTags: ['gpu'], minVramMb: 16_384 });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Multi-hop propagation is deferred; today peers more than one hop
|
|
30
|
+
* away are not visible.
|
|
31
|
+
*/
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.SCOPE_SUBNET_LOCAL = exports.SCOPE_REGION_PREFIX = exports.SCOPE_TENANT_PREFIX = void 0;
|
|
34
|
+
exports.capabilitySetToNapi = capabilitySetToNapi;
|
|
35
|
+
exports.capabilityFilterToNapi = capabilityFilterToNapi;
|
|
36
|
+
exports.scopeFilterToNapi = scopeFilterToNapi;
|
|
37
|
+
exports.withTenantScope = withTenantScope;
|
|
38
|
+
exports.withRegionScope = withRegionScope;
|
|
39
|
+
exports.withSubnetLocalScope = withSubnetLocalScope;
|
|
40
|
+
function gpuToNapi(g) {
|
|
41
|
+
return {
|
|
42
|
+
vendor: g.vendor,
|
|
43
|
+
model: g.model,
|
|
44
|
+
vramGb: g.vramGb,
|
|
45
|
+
computeUnits: g.computeUnits,
|
|
46
|
+
tensorCores: g.tensorCores,
|
|
47
|
+
fp16TflopsX10: g.fp16TflopsX10,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function acceleratorToNapi(a) {
|
|
51
|
+
return {
|
|
52
|
+
kind: a.kind,
|
|
53
|
+
model: a.model,
|
|
54
|
+
memoryGb: a.memoryGb,
|
|
55
|
+
topsX10: a.topsX10,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function hardwareToNapi(h) {
|
|
59
|
+
return {
|
|
60
|
+
cpuCores: h.cpuCores,
|
|
61
|
+
cpuThreads: h.cpuThreads,
|
|
62
|
+
memoryGb: h.memoryGb,
|
|
63
|
+
gpu: h.gpu ? gpuToNapi(h.gpu) : undefined,
|
|
64
|
+
additionalGpus: h.additionalGpus?.map(gpuToNapi),
|
|
65
|
+
storageGb: h.storageGb,
|
|
66
|
+
networkGbps: h.networkGbps,
|
|
67
|
+
accelerators: h.accelerators?.map(acceleratorToNapi),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function pairToArray(p) {
|
|
71
|
+
return [p[0], p[1]];
|
|
72
|
+
}
|
|
73
|
+
function softwareToNapi(s) {
|
|
74
|
+
return {
|
|
75
|
+
os: s.os,
|
|
76
|
+
osVersion: s.osVersion,
|
|
77
|
+
runtimes: s.runtimes?.map(pairToArray),
|
|
78
|
+
frameworks: s.frameworks?.map(pairToArray),
|
|
79
|
+
cudaVersion: s.cudaVersion,
|
|
80
|
+
drivers: s.drivers?.map(pairToArray),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function modelToNapi(m) {
|
|
84
|
+
return {
|
|
85
|
+
modelId: m.modelId,
|
|
86
|
+
family: m.family,
|
|
87
|
+
parametersBX10: m.parametersBX10,
|
|
88
|
+
contextLength: m.contextLength,
|
|
89
|
+
quantization: m.quantization,
|
|
90
|
+
modalities: m.modalities,
|
|
91
|
+
tokensPerSec: m.tokensPerSec,
|
|
92
|
+
loaded: m.loaded,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function toolToNapi(t) {
|
|
96
|
+
return {
|
|
97
|
+
toolId: t.toolId,
|
|
98
|
+
name: t.name,
|
|
99
|
+
version: t.version,
|
|
100
|
+
inputSchema: t.inputSchema,
|
|
101
|
+
outputSchema: t.outputSchema,
|
|
102
|
+
requires: t.requires,
|
|
103
|
+
estimatedTimeMs: t.estimatedTimeMs,
|
|
104
|
+
stateless: t.stateless,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function capabilitySetToNapi(caps) {
|
|
108
|
+
return {
|
|
109
|
+
hardware: caps.hardware ? hardwareToNapi(caps.hardware) : undefined,
|
|
110
|
+
software: caps.software ? softwareToNapi(caps.software) : undefined,
|
|
111
|
+
models: caps.models?.map(modelToNapi),
|
|
112
|
+
tools: caps.tools?.map(toolToNapi),
|
|
113
|
+
tags: caps.tags,
|
|
114
|
+
limits: caps.limits,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function capabilityFilterToNapi(f) {
|
|
118
|
+
return {
|
|
119
|
+
requireTags: f.requireTags,
|
|
120
|
+
requireModels: f.requireModels,
|
|
121
|
+
requireTools: f.requireTools,
|
|
122
|
+
minMemoryMb: f.minMemoryMb,
|
|
123
|
+
requireGpu: f.requireGpu,
|
|
124
|
+
gpuVendor: f.gpuVendor,
|
|
125
|
+
minVramMb: f.minVramMb,
|
|
126
|
+
minContextLength: f.minContextLength,
|
|
127
|
+
requireModalities: f.requireModalities,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function scopeFilterToNapi(s) {
|
|
131
|
+
switch (s.kind) {
|
|
132
|
+
case 'any':
|
|
133
|
+
case 'globalOnly':
|
|
134
|
+
case 'sameSubnet':
|
|
135
|
+
return { kind: s.kind };
|
|
136
|
+
case 'tenant':
|
|
137
|
+
return { kind: 'tenant', tenant: s.tenant };
|
|
138
|
+
case 'tenants':
|
|
139
|
+
return { kind: 'tenants', tenants: s.tenants };
|
|
140
|
+
case 'region':
|
|
141
|
+
return { kind: 'region', region: s.region };
|
|
142
|
+
case 'regions':
|
|
143
|
+
return { kind: 'regions', regions: s.regions };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// =====================================================
|
|
147
|
+
// Reserved scope tag helpers
|
|
148
|
+
// =====================================================
|
|
149
|
+
/** Reserved tag prefix for tenant-scoped announcements. */
|
|
150
|
+
exports.SCOPE_TENANT_PREFIX = 'scope:tenant:';
|
|
151
|
+
/** Reserved tag prefix for region-scoped announcements. */
|
|
152
|
+
exports.SCOPE_REGION_PREFIX = 'scope:region:';
|
|
153
|
+
/** Reserved tag marking an announcement subnet-local. */
|
|
154
|
+
exports.SCOPE_SUBNET_LOCAL = 'scope:subnet-local';
|
|
155
|
+
/**
|
|
156
|
+
* Append a `scope:tenant:<id>` tag to a tag list. Idempotent —
|
|
157
|
+
* safe to call repeatedly with the same id. Empty `tenantId` is a
|
|
158
|
+
* no-op.
|
|
159
|
+
*/
|
|
160
|
+
function withTenantScope(tags, tenantId) {
|
|
161
|
+
if (!tenantId)
|
|
162
|
+
return tags ?? [];
|
|
163
|
+
const tag = `${exports.SCOPE_TENANT_PREFIX}${tenantId}`;
|
|
164
|
+
const list = tags ?? [];
|
|
165
|
+
return list.includes(tag) ? list : [...list, tag];
|
|
166
|
+
}
|
|
167
|
+
/** Append a `scope:region:<name>` tag to a tag list. Idempotent. */
|
|
168
|
+
function withRegionScope(tags, region) {
|
|
169
|
+
if (!region)
|
|
170
|
+
return tags ?? [];
|
|
171
|
+
const tag = `${exports.SCOPE_REGION_PREFIX}${region}`;
|
|
172
|
+
const list = tags ?? [];
|
|
173
|
+
return list.includes(tag) ? list : [...list, tag];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Append the `scope:subnet-local` tag to a tag list. Idempotent.
|
|
177
|
+
* Strictest form wins on the resolver — when this tag is present,
|
|
178
|
+
* tenant/region tags on the same set are ignored by
|
|
179
|
+
* `CapabilityScope`.
|
|
180
|
+
*/
|
|
181
|
+
function withSubnetLocalScope(tags) {
|
|
182
|
+
const list = tags ?? [];
|
|
183
|
+
return list.includes(exports.SCOPE_SUBNET_LOCAL)
|
|
184
|
+
? list
|
|
185
|
+
: [...list, exports.SCOPE_SUBNET_LOCAL];
|
|
186
|
+
}
|