@reaatech/media-pipeline-mcp-provider-core 0.3.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/LICENSE +21 -0
- package/README.md +476 -0
- package/dist/index.cjs +529 -0
- package/dist/index.d.cts +262 -0
- package/dist/index.d.ts +262 -0
- package/dist/index.js +498 -0
- package/package.json +49 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { ArtifactType } from '@reaatech/media-pipeline-mcp-core';
|
|
2
|
+
import { ArtifactStore } from '@reaatech/media-pipeline-mcp-storage';
|
|
3
|
+
|
|
4
|
+
interface ProviderInput {
|
|
5
|
+
operation: string;
|
|
6
|
+
params: Record<string, unknown>;
|
|
7
|
+
config: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
interface ProviderOutput {
|
|
10
|
+
data: Buffer | ReadableStream;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
metadata: Record<string, unknown>;
|
|
13
|
+
costUsd?: number;
|
|
14
|
+
durationMs?: number;
|
|
15
|
+
}
|
|
16
|
+
interface ProviderHealth {
|
|
17
|
+
healthy: boolean;
|
|
18
|
+
latency?: number;
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
interface CostEstimate {
|
|
22
|
+
costUsd: number;
|
|
23
|
+
currency: string;
|
|
24
|
+
breakdown?: Array<{
|
|
25
|
+
component: string;
|
|
26
|
+
costUsd: number;
|
|
27
|
+
}>;
|
|
28
|
+
estimatedDurationMs?: number;
|
|
29
|
+
}
|
|
30
|
+
interface CacheConfig {
|
|
31
|
+
mode: 'use' | 'refresh' | 'skip';
|
|
32
|
+
ttlSeconds?: number;
|
|
33
|
+
scope?: 'global' | 'tenant';
|
|
34
|
+
}
|
|
35
|
+
interface CacheEntry {
|
|
36
|
+
key: string;
|
|
37
|
+
artifactIds: string[];
|
|
38
|
+
outputs: Record<string, unknown>;
|
|
39
|
+
costUsd: number;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
expiresAt: string;
|
|
42
|
+
hitCount: number;
|
|
43
|
+
}
|
|
44
|
+
interface ProviderCacheConfig {
|
|
45
|
+
deterministicParams: string[];
|
|
46
|
+
nonDeterministicParams: string[];
|
|
47
|
+
normalize: (inputs: Record<string, unknown>) => Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
interface WebhookPayload {
|
|
50
|
+
jobId: string;
|
|
51
|
+
status: 'completed' | 'failed' | 'progress';
|
|
52
|
+
output?: unknown;
|
|
53
|
+
pct?: number;
|
|
54
|
+
error?: {
|
|
55
|
+
code: string;
|
|
56
|
+
message: string;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
type RouterStrategy = 'first-success' | 'cheapest-acceptable' | 'fastest';
|
|
60
|
+
interface RouteCandidate {
|
|
61
|
+
provider: string;
|
|
62
|
+
model: string;
|
|
63
|
+
maxQueueMs?: number;
|
|
64
|
+
maxUsd?: number;
|
|
65
|
+
inputOverrides?: Record<string, unknown>;
|
|
66
|
+
weight?: number;
|
|
67
|
+
}
|
|
68
|
+
interface RouteConfig {
|
|
69
|
+
strategy: RouterStrategy;
|
|
70
|
+
candidates: RouteCandidate[];
|
|
71
|
+
timeoutMs?: number;
|
|
72
|
+
healthTtlMs?: number;
|
|
73
|
+
}
|
|
74
|
+
interface RouteRejection {
|
|
75
|
+
candidate: RouteCandidate;
|
|
76
|
+
reason: 'over-budget' | 'unhealthy' | 'queue-full' | 'error' | 'cancelled' | 'fastest-ineligible';
|
|
77
|
+
detail?: string;
|
|
78
|
+
}
|
|
79
|
+
interface RouteDecision {
|
|
80
|
+
selected: RouteCandidate;
|
|
81
|
+
rejected: RouteRejection[];
|
|
82
|
+
estimate?: CostEstimate;
|
|
83
|
+
reason: string;
|
|
84
|
+
decidedAtMs: number;
|
|
85
|
+
}
|
|
86
|
+
type MeshFormat = 'glb' | 'fbx' | 'obj' | 'usdz' | 'ply';
|
|
87
|
+
interface MeshGenInput {
|
|
88
|
+
prompt?: string;
|
|
89
|
+
sourceArtifactId?: string;
|
|
90
|
+
format: MeshFormat;
|
|
91
|
+
polyBudget?: number;
|
|
92
|
+
topology?: 'quads' | 'tris';
|
|
93
|
+
texture?: TextureConfig;
|
|
94
|
+
animated?: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface TextureConfig {
|
|
97
|
+
enabled: boolean;
|
|
98
|
+
pbr?: boolean;
|
|
99
|
+
resolution?: 512 | 1024 | 2048 | 4096;
|
|
100
|
+
unwrap?: 'auto' | 'preserve-source';
|
|
101
|
+
}
|
|
102
|
+
interface MeshOutput {
|
|
103
|
+
artifactId: string;
|
|
104
|
+
format: MeshFormat;
|
|
105
|
+
polyCount: number;
|
|
106
|
+
hasTextures: boolean;
|
|
107
|
+
hasAnimation: boolean;
|
|
108
|
+
bboxMeters?: {
|
|
109
|
+
x: number;
|
|
110
|
+
y: number;
|
|
111
|
+
z: number;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
interface PricingUnit {
|
|
115
|
+
perUnit: number;
|
|
116
|
+
unit?: string;
|
|
117
|
+
}
|
|
118
|
+
interface PricingEntry {
|
|
119
|
+
input: PricingUnit;
|
|
120
|
+
output?: PricingUnit;
|
|
121
|
+
expectedDurationMs?: number;
|
|
122
|
+
/** Optional per-step cost multiplier (e.g. Stability's diffusion steps). */
|
|
123
|
+
perStep?: number;
|
|
124
|
+
}
|
|
125
|
+
/** `pricing[operation][model] => PricingEntry`. */
|
|
126
|
+
type PricingTable = Record<string, Record<string, PricingEntry>>;
|
|
127
|
+
interface MediaProviderLike {
|
|
128
|
+
readonly name: string;
|
|
129
|
+
readonly supportedOperations: string[];
|
|
130
|
+
estimateCost(input: ProviderInput): Promise<CostEstimate>;
|
|
131
|
+
execute(input: ProviderInput): Promise<ProviderOutput>;
|
|
132
|
+
healthCheck?(): Promise<ProviderHealth>;
|
|
133
|
+
supportsStreaming?: ReadonlySet<string>;
|
|
134
|
+
supportsWebhooks?: boolean;
|
|
135
|
+
webhookSignatureKey?(): Promise<string>;
|
|
136
|
+
parseWebhookPayload?(headers: Record<string, string>, body: string): Promise<WebhookPayload>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
declare abstract class MediaProvider {
|
|
140
|
+
abstract readonly name: string;
|
|
141
|
+
abstract readonly supportedOperations: string[];
|
|
142
|
+
/** F2: per-provider cache config. Subclasses override to declare deterministic & non-deterministic params. */
|
|
143
|
+
static cacheConfig: ProviderCacheConfig;
|
|
144
|
+
/** F4/F5: cost estimation from public pricing */
|
|
145
|
+
abstract estimateCost(input: ProviderInput): Promise<CostEstimate>;
|
|
146
|
+
/** F6: set of operations that support streaming; absent = no streaming */
|
|
147
|
+
supportsStreaming?: ReadonlySet<string>;
|
|
148
|
+
/** F7: whether this provider supports webhook callbacks */
|
|
149
|
+
supportsWebhooks?: boolean;
|
|
150
|
+
/** F7: derive the signature key for webhook verification */
|
|
151
|
+
webhookSignatureKey?(): Promise<string>;
|
|
152
|
+
/** F7: parse an incoming webhook payload */
|
|
153
|
+
parseWebhookPayload?(headers: Record<string, string>, body: string): Promise<WebhookPayload>;
|
|
154
|
+
protected storage?: ArtifactStore;
|
|
155
|
+
protected retryConfig: {
|
|
156
|
+
maxRetries: number;
|
|
157
|
+
baseDelay: number;
|
|
158
|
+
maxDelay: number;
|
|
159
|
+
};
|
|
160
|
+
/** F2: in-memory cache store */
|
|
161
|
+
protected cacheStore: Map<string, CacheEntry>;
|
|
162
|
+
setStorage(storage: ArtifactStore): void;
|
|
163
|
+
healthCheck?(): Promise<ProviderHealth>;
|
|
164
|
+
abstract execute(input: ProviderInput): Promise<ProviderOutput>;
|
|
165
|
+
/**
|
|
166
|
+
* F2: execute with optional caching layer.
|
|
167
|
+
*
|
|
168
|
+
* Resolves cacheConfig:
|
|
169
|
+
* - explicit cacheConfig wins
|
|
170
|
+
* - else fall back to `defaultCacheConfigForOperation(input)` (per-op default; plan §F2)
|
|
171
|
+
*
|
|
172
|
+
* Mode semantics:
|
|
173
|
+
* - 'skip' — bypass cache entirely (no read, no write).
|
|
174
|
+
* - 'use' — read first; on miss, execute and store.
|
|
175
|
+
* - 'refresh' — always execute and store the fresh result (replace any existing entry).
|
|
176
|
+
*
|
|
177
|
+
* Key formula:
|
|
178
|
+
* sha256(provider :: modelId :: modelVersion :: scopeTag :: canonicalJson(deterministicInputs))
|
|
179
|
+
* where deterministicInputs = normalize(input.params filtered by ProviderCacheConfig.deterministicParams).
|
|
180
|
+
* When deterministicParams is empty (provider didn't override), all params participate.
|
|
181
|
+
*/
|
|
182
|
+
executeWithCache(input: ProviderInput, cacheConfig?: CacheConfig): Promise<ProviderOutput>;
|
|
183
|
+
/** Per-plan defaults when caller omits cacheConfig (F2 §"Backwards-compat" table). */
|
|
184
|
+
protected defaultCacheConfigForOperation(input: ProviderInput): CacheConfig;
|
|
185
|
+
/**
|
|
186
|
+
* F2: cache key — provider :: modelId :: modelVersion :: scopeTag :: deterministic-only inputs.
|
|
187
|
+
*
|
|
188
|
+
* `modelId` is read from input.params.model (or input.config.model); `modelVersion` from
|
|
189
|
+
* input.params.model_version (or model_id when it embeds a version like 'flux-pro-1.1').
|
|
190
|
+
* Scope tag: 'global' or `tenant:<id>` based on cacheConfig.scope. Tenant scope requires
|
|
191
|
+
* a tenantId on input.config; absence falls back to 'global' with a warning.
|
|
192
|
+
*/
|
|
193
|
+
protected computeCacheKey(input: ProviderInput, cacheConfig?: CacheConfig): string;
|
|
194
|
+
/**
|
|
195
|
+
* Drop params not in `deterministicParams`. If the list is empty (provider didn't override),
|
|
196
|
+
* fall back to "all params except those in `nonDeterministicParams`" — and if both lists are
|
|
197
|
+
* empty, hash every param (legacy behavior).
|
|
198
|
+
*/
|
|
199
|
+
private filterDeterministic;
|
|
200
|
+
/** F2: canonical JSON: sorted keys, no whitespace, no trailing zeros */
|
|
201
|
+
protected canonicalJson(obj: unknown): string;
|
|
202
|
+
/** F2: strip trailing zeros from numbers */
|
|
203
|
+
private canonicalNumber;
|
|
204
|
+
executeWithRetry(input: ProviderInput): Promise<ProviderOutput>;
|
|
205
|
+
private executeWithRetryImpl;
|
|
206
|
+
protected isNonRetryableError(error: unknown): boolean;
|
|
207
|
+
protected generateArtifactId(): string;
|
|
208
|
+
storeArtifact(data: Buffer | ReadableStream, type: ArtifactType, mimeType: string, metadata: Record<string, unknown>, sourceStep?: string): Promise<string>;
|
|
209
|
+
}
|
|
210
|
+
declare function defineProvider<T extends MediaProvider>(providerClass: new (...args: unknown[]) => T): new (...args: unknown[]) => T;
|
|
211
|
+
|
|
212
|
+
declare class RouterNoCandidatesError extends Error {
|
|
213
|
+
readonly code = "ROUTER_NO_CANDIDATES";
|
|
214
|
+
constructor();
|
|
215
|
+
}
|
|
216
|
+
declare class RouterAllCandidatesFailedError extends Error {
|
|
217
|
+
readonly code = "ROUTER_ALL_CANDIDATES_FAILED";
|
|
218
|
+
readonly rejections: RouteRejection[];
|
|
219
|
+
constructor(rejections: RouteRejection[]);
|
|
220
|
+
}
|
|
221
|
+
interface RouterContext {
|
|
222
|
+
estimateCost(candidate: RouteCandidate, inputs: ProviderInput): Promise<CostEstimate>;
|
|
223
|
+
health(candidate: RouteCandidate): Promise<{
|
|
224
|
+
healthy: boolean;
|
|
225
|
+
latencyMs?: number;
|
|
226
|
+
queueDepth?: number;
|
|
227
|
+
}>;
|
|
228
|
+
execute(candidate: RouteCandidate, inputs: ProviderInput, signal: AbortSignal): Promise<ProviderOutput>;
|
|
229
|
+
/**
|
|
230
|
+
* Expected duration in ms for this candidate's pricing tier. Sourced from per-provider
|
|
231
|
+
* pricing.json. Return undefined when unknown — that disqualifies the candidate from
|
|
232
|
+
* `fastest` (the strategy needs an upper bound to enforce its <5s rule).
|
|
233
|
+
*/
|
|
234
|
+
expectedDurationMs?(candidate: RouteCandidate, inputs: ProviderInput): number | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* Per-candidate queue depth from a fresh probe. If absent, the queue check is skipped.
|
|
237
|
+
* Most providers don't expose queue depth; fal does.
|
|
238
|
+
*/
|
|
239
|
+
queueMs?(candidate: RouteCandidate): Promise<number | undefined>;
|
|
240
|
+
}
|
|
241
|
+
declare class Router {
|
|
242
|
+
private ctx;
|
|
243
|
+
private healthCache;
|
|
244
|
+
constructor(ctx: RouterContext);
|
|
245
|
+
route(config: RouteConfig, inputs: ProviderInput): Promise<{
|
|
246
|
+
decision: RouteDecision;
|
|
247
|
+
output: ProviderOutput;
|
|
248
|
+
}>;
|
|
249
|
+
/**
|
|
250
|
+
* Cached health probe. Cache key is provider+model so we share the result across
|
|
251
|
+
* routes that mention the same candidate. TTL defaults to 30s; per-route override
|
|
252
|
+
* via RouteConfig.healthTtlMs.
|
|
253
|
+
*/
|
|
254
|
+
private cachedHealth;
|
|
255
|
+
/** Merge candidate-specific input overrides into the step inputs. */
|
|
256
|
+
private applyInputOverrides;
|
|
257
|
+
private routeFirstSuccess;
|
|
258
|
+
private routeCheapestAcceptable;
|
|
259
|
+
private routeFastest;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { type CacheConfig, type CacheEntry, type CostEstimate, MediaProvider, type MediaProviderLike, type MeshFormat, type MeshGenInput, type MeshOutput, type PricingEntry, type PricingTable, type PricingUnit, type ProviderCacheConfig, type ProviderHealth, type ProviderInput, type ProviderOutput, type RouteCandidate, type RouteConfig, type RouteDecision, type RouteRejection, Router, RouterAllCandidatesFailedError, type RouterContext, RouterNoCandidatesError, type RouterStrategy, type TextureConfig, type WebhookPayload, defineProvider };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { ArtifactType } from '@reaatech/media-pipeline-mcp-core';
|
|
2
|
+
import { ArtifactStore } from '@reaatech/media-pipeline-mcp-storage';
|
|
3
|
+
|
|
4
|
+
interface ProviderInput {
|
|
5
|
+
operation: string;
|
|
6
|
+
params: Record<string, unknown>;
|
|
7
|
+
config: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
interface ProviderOutput {
|
|
10
|
+
data: Buffer | ReadableStream;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
metadata: Record<string, unknown>;
|
|
13
|
+
costUsd?: number;
|
|
14
|
+
durationMs?: number;
|
|
15
|
+
}
|
|
16
|
+
interface ProviderHealth {
|
|
17
|
+
healthy: boolean;
|
|
18
|
+
latency?: number;
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
interface CostEstimate {
|
|
22
|
+
costUsd: number;
|
|
23
|
+
currency: string;
|
|
24
|
+
breakdown?: Array<{
|
|
25
|
+
component: string;
|
|
26
|
+
costUsd: number;
|
|
27
|
+
}>;
|
|
28
|
+
estimatedDurationMs?: number;
|
|
29
|
+
}
|
|
30
|
+
interface CacheConfig {
|
|
31
|
+
mode: 'use' | 'refresh' | 'skip';
|
|
32
|
+
ttlSeconds?: number;
|
|
33
|
+
scope?: 'global' | 'tenant';
|
|
34
|
+
}
|
|
35
|
+
interface CacheEntry {
|
|
36
|
+
key: string;
|
|
37
|
+
artifactIds: string[];
|
|
38
|
+
outputs: Record<string, unknown>;
|
|
39
|
+
costUsd: number;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
expiresAt: string;
|
|
42
|
+
hitCount: number;
|
|
43
|
+
}
|
|
44
|
+
interface ProviderCacheConfig {
|
|
45
|
+
deterministicParams: string[];
|
|
46
|
+
nonDeterministicParams: string[];
|
|
47
|
+
normalize: (inputs: Record<string, unknown>) => Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
interface WebhookPayload {
|
|
50
|
+
jobId: string;
|
|
51
|
+
status: 'completed' | 'failed' | 'progress';
|
|
52
|
+
output?: unknown;
|
|
53
|
+
pct?: number;
|
|
54
|
+
error?: {
|
|
55
|
+
code: string;
|
|
56
|
+
message: string;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
type RouterStrategy = 'first-success' | 'cheapest-acceptable' | 'fastest';
|
|
60
|
+
interface RouteCandidate {
|
|
61
|
+
provider: string;
|
|
62
|
+
model: string;
|
|
63
|
+
maxQueueMs?: number;
|
|
64
|
+
maxUsd?: number;
|
|
65
|
+
inputOverrides?: Record<string, unknown>;
|
|
66
|
+
weight?: number;
|
|
67
|
+
}
|
|
68
|
+
interface RouteConfig {
|
|
69
|
+
strategy: RouterStrategy;
|
|
70
|
+
candidates: RouteCandidate[];
|
|
71
|
+
timeoutMs?: number;
|
|
72
|
+
healthTtlMs?: number;
|
|
73
|
+
}
|
|
74
|
+
interface RouteRejection {
|
|
75
|
+
candidate: RouteCandidate;
|
|
76
|
+
reason: 'over-budget' | 'unhealthy' | 'queue-full' | 'error' | 'cancelled' | 'fastest-ineligible';
|
|
77
|
+
detail?: string;
|
|
78
|
+
}
|
|
79
|
+
interface RouteDecision {
|
|
80
|
+
selected: RouteCandidate;
|
|
81
|
+
rejected: RouteRejection[];
|
|
82
|
+
estimate?: CostEstimate;
|
|
83
|
+
reason: string;
|
|
84
|
+
decidedAtMs: number;
|
|
85
|
+
}
|
|
86
|
+
type MeshFormat = 'glb' | 'fbx' | 'obj' | 'usdz' | 'ply';
|
|
87
|
+
interface MeshGenInput {
|
|
88
|
+
prompt?: string;
|
|
89
|
+
sourceArtifactId?: string;
|
|
90
|
+
format: MeshFormat;
|
|
91
|
+
polyBudget?: number;
|
|
92
|
+
topology?: 'quads' | 'tris';
|
|
93
|
+
texture?: TextureConfig;
|
|
94
|
+
animated?: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface TextureConfig {
|
|
97
|
+
enabled: boolean;
|
|
98
|
+
pbr?: boolean;
|
|
99
|
+
resolution?: 512 | 1024 | 2048 | 4096;
|
|
100
|
+
unwrap?: 'auto' | 'preserve-source';
|
|
101
|
+
}
|
|
102
|
+
interface MeshOutput {
|
|
103
|
+
artifactId: string;
|
|
104
|
+
format: MeshFormat;
|
|
105
|
+
polyCount: number;
|
|
106
|
+
hasTextures: boolean;
|
|
107
|
+
hasAnimation: boolean;
|
|
108
|
+
bboxMeters?: {
|
|
109
|
+
x: number;
|
|
110
|
+
y: number;
|
|
111
|
+
z: number;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
interface PricingUnit {
|
|
115
|
+
perUnit: number;
|
|
116
|
+
unit?: string;
|
|
117
|
+
}
|
|
118
|
+
interface PricingEntry {
|
|
119
|
+
input: PricingUnit;
|
|
120
|
+
output?: PricingUnit;
|
|
121
|
+
expectedDurationMs?: number;
|
|
122
|
+
/** Optional per-step cost multiplier (e.g. Stability's diffusion steps). */
|
|
123
|
+
perStep?: number;
|
|
124
|
+
}
|
|
125
|
+
/** `pricing[operation][model] => PricingEntry`. */
|
|
126
|
+
type PricingTable = Record<string, Record<string, PricingEntry>>;
|
|
127
|
+
interface MediaProviderLike {
|
|
128
|
+
readonly name: string;
|
|
129
|
+
readonly supportedOperations: string[];
|
|
130
|
+
estimateCost(input: ProviderInput): Promise<CostEstimate>;
|
|
131
|
+
execute(input: ProviderInput): Promise<ProviderOutput>;
|
|
132
|
+
healthCheck?(): Promise<ProviderHealth>;
|
|
133
|
+
supportsStreaming?: ReadonlySet<string>;
|
|
134
|
+
supportsWebhooks?: boolean;
|
|
135
|
+
webhookSignatureKey?(): Promise<string>;
|
|
136
|
+
parseWebhookPayload?(headers: Record<string, string>, body: string): Promise<WebhookPayload>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
declare abstract class MediaProvider {
|
|
140
|
+
abstract readonly name: string;
|
|
141
|
+
abstract readonly supportedOperations: string[];
|
|
142
|
+
/** F2: per-provider cache config. Subclasses override to declare deterministic & non-deterministic params. */
|
|
143
|
+
static cacheConfig: ProviderCacheConfig;
|
|
144
|
+
/** F4/F5: cost estimation from public pricing */
|
|
145
|
+
abstract estimateCost(input: ProviderInput): Promise<CostEstimate>;
|
|
146
|
+
/** F6: set of operations that support streaming; absent = no streaming */
|
|
147
|
+
supportsStreaming?: ReadonlySet<string>;
|
|
148
|
+
/** F7: whether this provider supports webhook callbacks */
|
|
149
|
+
supportsWebhooks?: boolean;
|
|
150
|
+
/** F7: derive the signature key for webhook verification */
|
|
151
|
+
webhookSignatureKey?(): Promise<string>;
|
|
152
|
+
/** F7: parse an incoming webhook payload */
|
|
153
|
+
parseWebhookPayload?(headers: Record<string, string>, body: string): Promise<WebhookPayload>;
|
|
154
|
+
protected storage?: ArtifactStore;
|
|
155
|
+
protected retryConfig: {
|
|
156
|
+
maxRetries: number;
|
|
157
|
+
baseDelay: number;
|
|
158
|
+
maxDelay: number;
|
|
159
|
+
};
|
|
160
|
+
/** F2: in-memory cache store */
|
|
161
|
+
protected cacheStore: Map<string, CacheEntry>;
|
|
162
|
+
setStorage(storage: ArtifactStore): void;
|
|
163
|
+
healthCheck?(): Promise<ProviderHealth>;
|
|
164
|
+
abstract execute(input: ProviderInput): Promise<ProviderOutput>;
|
|
165
|
+
/**
|
|
166
|
+
* F2: execute with optional caching layer.
|
|
167
|
+
*
|
|
168
|
+
* Resolves cacheConfig:
|
|
169
|
+
* - explicit cacheConfig wins
|
|
170
|
+
* - else fall back to `defaultCacheConfigForOperation(input)` (per-op default; plan §F2)
|
|
171
|
+
*
|
|
172
|
+
* Mode semantics:
|
|
173
|
+
* - 'skip' — bypass cache entirely (no read, no write).
|
|
174
|
+
* - 'use' — read first; on miss, execute and store.
|
|
175
|
+
* - 'refresh' — always execute and store the fresh result (replace any existing entry).
|
|
176
|
+
*
|
|
177
|
+
* Key formula:
|
|
178
|
+
* sha256(provider :: modelId :: modelVersion :: scopeTag :: canonicalJson(deterministicInputs))
|
|
179
|
+
* where deterministicInputs = normalize(input.params filtered by ProviderCacheConfig.deterministicParams).
|
|
180
|
+
* When deterministicParams is empty (provider didn't override), all params participate.
|
|
181
|
+
*/
|
|
182
|
+
executeWithCache(input: ProviderInput, cacheConfig?: CacheConfig): Promise<ProviderOutput>;
|
|
183
|
+
/** Per-plan defaults when caller omits cacheConfig (F2 §"Backwards-compat" table). */
|
|
184
|
+
protected defaultCacheConfigForOperation(input: ProviderInput): CacheConfig;
|
|
185
|
+
/**
|
|
186
|
+
* F2: cache key — provider :: modelId :: modelVersion :: scopeTag :: deterministic-only inputs.
|
|
187
|
+
*
|
|
188
|
+
* `modelId` is read from input.params.model (or input.config.model); `modelVersion` from
|
|
189
|
+
* input.params.model_version (or model_id when it embeds a version like 'flux-pro-1.1').
|
|
190
|
+
* Scope tag: 'global' or `tenant:<id>` based on cacheConfig.scope. Tenant scope requires
|
|
191
|
+
* a tenantId on input.config; absence falls back to 'global' with a warning.
|
|
192
|
+
*/
|
|
193
|
+
protected computeCacheKey(input: ProviderInput, cacheConfig?: CacheConfig): string;
|
|
194
|
+
/**
|
|
195
|
+
* Drop params not in `deterministicParams`. If the list is empty (provider didn't override),
|
|
196
|
+
* fall back to "all params except those in `nonDeterministicParams`" — and if both lists are
|
|
197
|
+
* empty, hash every param (legacy behavior).
|
|
198
|
+
*/
|
|
199
|
+
private filterDeterministic;
|
|
200
|
+
/** F2: canonical JSON: sorted keys, no whitespace, no trailing zeros */
|
|
201
|
+
protected canonicalJson(obj: unknown): string;
|
|
202
|
+
/** F2: strip trailing zeros from numbers */
|
|
203
|
+
private canonicalNumber;
|
|
204
|
+
executeWithRetry(input: ProviderInput): Promise<ProviderOutput>;
|
|
205
|
+
private executeWithRetryImpl;
|
|
206
|
+
protected isNonRetryableError(error: unknown): boolean;
|
|
207
|
+
protected generateArtifactId(): string;
|
|
208
|
+
storeArtifact(data: Buffer | ReadableStream, type: ArtifactType, mimeType: string, metadata: Record<string, unknown>, sourceStep?: string): Promise<string>;
|
|
209
|
+
}
|
|
210
|
+
declare function defineProvider<T extends MediaProvider>(providerClass: new (...args: unknown[]) => T): new (...args: unknown[]) => T;
|
|
211
|
+
|
|
212
|
+
declare class RouterNoCandidatesError extends Error {
|
|
213
|
+
readonly code = "ROUTER_NO_CANDIDATES";
|
|
214
|
+
constructor();
|
|
215
|
+
}
|
|
216
|
+
declare class RouterAllCandidatesFailedError extends Error {
|
|
217
|
+
readonly code = "ROUTER_ALL_CANDIDATES_FAILED";
|
|
218
|
+
readonly rejections: RouteRejection[];
|
|
219
|
+
constructor(rejections: RouteRejection[]);
|
|
220
|
+
}
|
|
221
|
+
interface RouterContext {
|
|
222
|
+
estimateCost(candidate: RouteCandidate, inputs: ProviderInput): Promise<CostEstimate>;
|
|
223
|
+
health(candidate: RouteCandidate): Promise<{
|
|
224
|
+
healthy: boolean;
|
|
225
|
+
latencyMs?: number;
|
|
226
|
+
queueDepth?: number;
|
|
227
|
+
}>;
|
|
228
|
+
execute(candidate: RouteCandidate, inputs: ProviderInput, signal: AbortSignal): Promise<ProviderOutput>;
|
|
229
|
+
/**
|
|
230
|
+
* Expected duration in ms for this candidate's pricing tier. Sourced from per-provider
|
|
231
|
+
* pricing.json. Return undefined when unknown — that disqualifies the candidate from
|
|
232
|
+
* `fastest` (the strategy needs an upper bound to enforce its <5s rule).
|
|
233
|
+
*/
|
|
234
|
+
expectedDurationMs?(candidate: RouteCandidate, inputs: ProviderInput): number | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* Per-candidate queue depth from a fresh probe. If absent, the queue check is skipped.
|
|
237
|
+
* Most providers don't expose queue depth; fal does.
|
|
238
|
+
*/
|
|
239
|
+
queueMs?(candidate: RouteCandidate): Promise<number | undefined>;
|
|
240
|
+
}
|
|
241
|
+
declare class Router {
|
|
242
|
+
private ctx;
|
|
243
|
+
private healthCache;
|
|
244
|
+
constructor(ctx: RouterContext);
|
|
245
|
+
route(config: RouteConfig, inputs: ProviderInput): Promise<{
|
|
246
|
+
decision: RouteDecision;
|
|
247
|
+
output: ProviderOutput;
|
|
248
|
+
}>;
|
|
249
|
+
/**
|
|
250
|
+
* Cached health probe. Cache key is provider+model so we share the result across
|
|
251
|
+
* routes that mention the same candidate. TTL defaults to 30s; per-route override
|
|
252
|
+
* via RouteConfig.healthTtlMs.
|
|
253
|
+
*/
|
|
254
|
+
private cachedHealth;
|
|
255
|
+
/** Merge candidate-specific input overrides into the step inputs. */
|
|
256
|
+
private applyInputOverrides;
|
|
257
|
+
private routeFirstSuccess;
|
|
258
|
+
private routeCheapestAcceptable;
|
|
259
|
+
private routeFastest;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { type CacheConfig, type CacheEntry, type CostEstimate, MediaProvider, type MediaProviderLike, type MeshFormat, type MeshGenInput, type MeshOutput, type PricingEntry, type PricingTable, type PricingUnit, type ProviderCacheConfig, type ProviderHealth, type ProviderInput, type ProviderOutput, type RouteCandidate, type RouteConfig, type RouteDecision, type RouteRejection, Router, RouterAllCandidatesFailedError, type RouterContext, RouterNoCandidatesError, type RouterStrategy, type TextureConfig, type WebhookPayload, defineProvider };
|