@tangle-network/tcloud 0.1.4 → 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.
@@ -0,0 +1,1117 @@
1
+ /** Core types for the tcloud SDK */
2
+ interface TCloudConfig {
3
+ /** API base URL (default: https://router.tangle.tools/v1) */
4
+ baseURL?: string;
5
+ /** Platform API URL for billing/keys (default: https://id.tangle.tools) */
6
+ platformURL?: string;
7
+ /** API key for standard (non-private) mode */
8
+ apiKey?: string;
9
+ /** Default model */
10
+ model?: string;
11
+ /** Operator routing preferences */
12
+ routing?: RoutingConfig;
13
+ /** Enable shielded (private) mode */
14
+ shielded?: ShieldedConfig | boolean;
15
+ /** Privacy proxy configuration for IP hiding */
16
+ privacy?: PrivacyConfig;
17
+ /** Spending limits and metering */
18
+ limits?: SpendingLimits;
19
+ /** Retry configuration for transient failures */
20
+ retry?: RetryConfig | false;
21
+ /** Default request timeout in ms (default: 60000). Set 0 to disable. */
22
+ timeout?: number;
23
+ }
24
+ interface RetryConfig {
25
+ /** Max retry attempts (default: 3) */
26
+ maxRetries?: number;
27
+ /** Initial backoff in ms (default: 500) */
28
+ initialBackoffMs?: number;
29
+ /** Max backoff in ms (default: 30000) */
30
+ maxBackoffMs?: number;
31
+ /** Backoff multiplier (default: 2) */
32
+ multiplier?: number;
33
+ /** HTTP status codes that trigger retry (default: [429, 500, 502, 503, 504]) */
34
+ retryableStatuses?: number[];
35
+ }
36
+ interface SpendingLimits {
37
+ /** Max USD to spend per request. Rejects if estimated cost exceeds this. */
38
+ maxCostPerRequest?: number;
39
+ /** Max USD to spend across all requests in this client's lifetime. Stops at limit. */
40
+ maxTotalSpend?: number;
41
+ /** Max requests allowed. Stops at limit. */
42
+ maxRequests?: number;
43
+ /** Callback when a limit is approached (80% threshold) */
44
+ onLimitWarning?: (info: {
45
+ type: 'cost' | 'total' | 'requests';
46
+ current: number;
47
+ limit: number;
48
+ }) => void;
49
+ /** Callback when a limit is hit (request blocked) */
50
+ onLimitReached?: (info: {
51
+ type: 'cost' | 'total' | 'requests';
52
+ current: number;
53
+ limit: number;
54
+ }) => void;
55
+ }
56
+ interface RoutingConfig {
57
+ /** Routing mode: 'operator' (Tangle operators only), 'provider' (direct APIs only), 'auto' (try operators, fall back to providers) */
58
+ mode?: 'operator' | 'provider' | 'auto';
59
+ /** Preferred operator slug or address */
60
+ prefer?: string;
61
+ /** Blueprint ID — route to operators under this Blueprint */
62
+ blueprintId?: string;
63
+ /** Service instance ID — route to a specific service instance */
64
+ serviceId?: string;
65
+ /** Routing strategy */
66
+ strategy?: 'lowest-latency' | 'lowest-price' | 'highest-reputation' | 'round-robin';
67
+ /** Region filter */
68
+ region?: string;
69
+ /** Fallback operator slugs (tried in order) */
70
+ fallback?: string[];
71
+ }
72
+ interface EmbeddingOptions {
73
+ model?: string;
74
+ input: string | string[];
75
+ }
76
+ interface EmbeddingResponse {
77
+ object: string;
78
+ data: {
79
+ object: string;
80
+ embedding: number[];
81
+ index: number;
82
+ }[];
83
+ model: string;
84
+ usage: {
85
+ prompt_tokens: number;
86
+ total_tokens: number;
87
+ };
88
+ }
89
+ interface ImageGenerateOptions {
90
+ model?: string;
91
+ prompt: string;
92
+ n?: number;
93
+ size?: string;
94
+ quality?: string;
95
+ response_format?: 'url' | 'b64_json';
96
+ }
97
+ interface ImageResponse {
98
+ created: number;
99
+ data: {
100
+ url?: string;
101
+ b64_json?: string;
102
+ revised_prompt?: string;
103
+ }[];
104
+ }
105
+ interface RerankOptions {
106
+ model?: string;
107
+ query: string;
108
+ documents: string[];
109
+ top_n?: number;
110
+ }
111
+ interface RerankResponse {
112
+ results: {
113
+ index: number;
114
+ relevance_score: number;
115
+ }[];
116
+ }
117
+ interface CompletionOptions {
118
+ model?: string;
119
+ prompt: string;
120
+ temperature?: number;
121
+ maxTokens?: number;
122
+ stop?: string | string[];
123
+ topP?: number;
124
+ }
125
+ interface CompletionResponse {
126
+ id: string;
127
+ object: string;
128
+ created: number;
129
+ model: string;
130
+ choices: {
131
+ text: string;
132
+ index: number;
133
+ finish_reason: string;
134
+ }[];
135
+ usage?: {
136
+ prompt_tokens: number;
137
+ completion_tokens: number;
138
+ total_tokens: number;
139
+ };
140
+ }
141
+ interface TranscriptionResponse {
142
+ text: string;
143
+ }
144
+ interface FineTuningJobOptions {
145
+ model: string;
146
+ training_file: string;
147
+ hyperparameters?: {
148
+ n_epochs?: number | 'auto';
149
+ batch_size?: number | 'auto';
150
+ learning_rate_multiplier?: number | 'auto';
151
+ };
152
+ suffix?: string;
153
+ }
154
+ interface FineTuningJob {
155
+ id: string;
156
+ object: string;
157
+ model: string;
158
+ status: string;
159
+ created_at: number;
160
+ finished_at: number | null;
161
+ fine_tuned_model: string | null;
162
+ error: {
163
+ code: string;
164
+ message: string;
165
+ } | null;
166
+ }
167
+ interface BatchRequest {
168
+ model: string;
169
+ messages: ChatMessage[];
170
+ temperature?: number;
171
+ max_tokens?: number;
172
+ }
173
+ interface BatchJobResponse {
174
+ id: string;
175
+ status: 'pending' | 'processing' | 'completed' | 'failed';
176
+ total_items: number;
177
+ completed: number;
178
+ failed: number;
179
+ results: ({
180
+ status: 'fulfilled';
181
+ data: ChatCompletion;
182
+ } | {
183
+ status: 'rejected';
184
+ error: string;
185
+ })[] | null;
186
+ error: string | null;
187
+ created_at: string;
188
+ completed_at: string | null;
189
+ }
190
+ interface VideoGenerateOptions {
191
+ model?: string;
192
+ prompt: string;
193
+ duration?: number;
194
+ resolution?: string;
195
+ }
196
+ interface VideoResponse {
197
+ id: string;
198
+ status: string;
199
+ url?: string;
200
+ error?: string;
201
+ }
202
+ /** Request body for POST /v1/avatar/generate */
203
+ interface AvatarGenerateRequest {
204
+ /** URL to narration audio (wav/mp3) */
205
+ audio_url: string;
206
+ /** URL to face image, OR omit and use avatar_id */
207
+ image_url?: string;
208
+ /** Preset avatar identifier (provider-specific) */
209
+ avatar_id?: string;
210
+ /** Target duration in seconds (capped by operator's max_duration_seconds) */
211
+ duration_seconds?: number;
212
+ /** Output format (default: "mp4") */
213
+ output_format?: string;
214
+ }
215
+ /** Response from POST /v1/avatar/generate (202 Accepted) */
216
+ interface AvatarGenerateResponse {
217
+ job_id: string;
218
+ status: 'queued' | 'processing' | 'completed' | 'failed';
219
+ result?: AvatarResult;
220
+ error?: string;
221
+ }
222
+ /** Result payload within a completed avatar job */
223
+ interface AvatarResult {
224
+ video_url: string;
225
+ duration_seconds: number;
226
+ format: string;
227
+ }
228
+ /** Response from GET /v1/avatar/jobs/:id */
229
+ interface AvatarJobStatus {
230
+ job_id: string;
231
+ status: 'queued' | 'processing' | 'completed' | 'failed';
232
+ result?: AvatarResult;
233
+ error?: string;
234
+ }
235
+ interface PrivacyConfig {
236
+ /** 'direct' — no proxy (default). 'relayer' — route through tcloud-relayer. 'socks5' — route through SOCKS5 proxy (e.g. Tor). */
237
+ mode: 'direct' | 'relayer' | 'socks5';
238
+ /** Relayer URL for 'relayer' mode (e.g. 'http://localhost:3030') */
239
+ relayerUrl?: string;
240
+ /**
241
+ * SOCKS5 proxy URL for 'socks5' mode (e.g. 'socks5://127.0.0.1:9050' for Tor).
242
+ * Requires `socks-proxy-agent` as an optional peer dependency.
243
+ */
244
+ socksProxy?: string;
245
+ }
246
+ interface ShieldedConfig {
247
+ /** Pre-existing spending private key (hex). If not set, generates ephemeral. */
248
+ spendingKey?: string;
249
+ /** Pre-existing commitment. If not set, derives from key. */
250
+ commitment?: string;
251
+ /** Chain ID (default: 3799 for Tangle testnet) */
252
+ chainId?: number;
253
+ /** ShieldedCredits contract address */
254
+ creditsAddress?: string;
255
+ /** Service ID for the blueprint */
256
+ serviceId?: bigint;
257
+ /** Privacy proxy configuration for IP hiding */
258
+ privacy?: PrivacyConfig;
259
+ }
260
+ interface ChatMessage {
261
+ role: 'system' | 'user' | 'assistant' | 'tool';
262
+ content: string;
263
+ name?: string;
264
+ }
265
+ /** Gateway-level options for routing, compliance, and inference strategies. */
266
+ interface GatewayOptions {
267
+ /** BYOK: per-request provider credentials. Zero markup. */
268
+ byok?: Record<string, Array<{
269
+ apiKey?: string;
270
+ }>>;
271
+ /** Route only through ZDR-verified providers. */
272
+ zeroDataRetention?: boolean;
273
+ /** Route only through providers that don't train on prompts. */
274
+ disallowPromptTraining?: boolean;
275
+ /** Inject cache_control markers for providers that need them. */
276
+ caching?: 'auto' | false;
277
+ /** Provider priority order. */
278
+ order?: string[];
279
+ /** Restrict to these providers only. */
280
+ only?: string[];
281
+ /** Fallback model list tried in order. */
282
+ models?: string[];
283
+ /** Per-provider or global timeout (ms, clamped 1s–120s). */
284
+ timeout?: number | Record<string, number>;
285
+ /** Smart routing hint. 'quality' auto-enables RSA. */
286
+ optimize?: 'cost' | 'latency' | 'quality';
287
+ /** Disable response cache for this request. */
288
+ cache?: boolean;
289
+ /**
290
+ * RSA / MoA: population-based quality amplification.
291
+ * Spawns N parallel calls, aggregates K at a time, refines over T rounds.
292
+ * Add `models` for Mixture-of-Agents (diverse models per slot).
293
+ */
294
+ rsa?: {
295
+ n?: number;
296
+ k?: number;
297
+ t?: number;
298
+ /** MoA: diverse models for generation (round-robin). Aggregation uses primary model. */
299
+ models?: string[];
300
+ };
301
+ /**
302
+ * Best-of-N: generate N candidates, score, return the winner.
303
+ * Scorer: webhook (your HTTP endpoint) or llm (LLM-as-judge).
304
+ */
305
+ bestOfN?: {
306
+ n?: number;
307
+ /** Diverse models for generation (round-robin). */
308
+ models?: string[];
309
+ scorer: {
310
+ type: 'webhook';
311
+ url: string;
312
+ timeout?: number;
313
+ } | {
314
+ type: 'llm';
315
+ model: string;
316
+ prompt: string;
317
+ };
318
+ };
319
+ }
320
+ /**
321
+ * Bridge options — route a single chat call through the Tangle Router's
322
+ * cli-bridge short-circuit. The bridge drives subscription-backed CLIs
323
+ * (Claude Code, Codex, Kimi Code, opencode) as OpenAI-compatible
324
+ * harnesses with persistent session resume.
325
+ *
326
+ * When `bridge` is set, the client:
327
+ * 1. Rewrites `model` to `bridge/<harness>/<model>` (or `bridge/<harness>`
328
+ * if no model is given — uses the harness default)
329
+ * 2. Injects `X-Bridge-Unlock` with the caller's unlock token
330
+ * 3. Injects `X-Resume` so follow-up calls with the same id resume
331
+ * the CLI's native session (no re-tokenizing prior turns)
332
+ * 4. Optionally injects BYOB headers `X-Bridge-Url` + `X-Bridge-Bearer`
333
+ * if the caller wants to target their own cli-bridge instance
334
+ * (requires the router to be deployed with CLI_BRIDGE_BYOB_ENABLED)
335
+ */
336
+ interface BridgeOptions {
337
+ /** Which harness to drive. Picks the backend on the bridge. */
338
+ harness: 'claude' | 'claudish' | 'codex' | 'opencode' | 'kimi' | 'openai' | 'anthropic' | 'moonshot' | 'zai';
339
+ /** Model id inside the harness (e.g. `sonnet`, `kimi-for-coding`, `gpt-5-codex`). Omit for harness default. */
340
+ model?: string;
341
+ /** Router-issued unlock token. Required unless operator has disabled the gate. */
342
+ unlock: string;
343
+ /** Stable caller-owned id for session resume. Map one id per logical conversation. */
344
+ resume?: string;
345
+ /** BYOB: point at your own cli-bridge instance. Router must have BYOB enabled. */
346
+ bridgeUrl?: string;
347
+ /** BYOB: bearer your cli-bridge expects. */
348
+ bridgeBearer?: string;
349
+ }
350
+ interface ChatOptions {
351
+ /** Model to use */
352
+ model?: string;
353
+ /** Messages */
354
+ messages: ChatMessage[];
355
+ /** Temperature (0-2) */
356
+ temperature?: number;
357
+ /** Max tokens to generate */
358
+ maxTokens?: number;
359
+ /** Stream response */
360
+ stream?: boolean;
361
+ /** Stop sequences */
362
+ stop?: string | string[];
363
+ /** Top-p sampling */
364
+ topP?: number;
365
+ /** Frequency penalty */
366
+ frequencyPenalty?: number;
367
+ /** Presence penalty */
368
+ presencePenalty?: number;
369
+ /** JSON mode */
370
+ responseFormat?: {
371
+ type: 'text' | 'json_object';
372
+ };
373
+ /** Tools / function calling */
374
+ tools?: any[];
375
+ /** Tool choice strategy or specific tool */
376
+ toolChoice?: 'none' | 'auto' | 'required' | {
377
+ type: 'function';
378
+ function: {
379
+ name: string;
380
+ };
381
+ };
382
+ /**
383
+ * Gateway options: routing, compliance, inference strategies (RSA/MoA/Best-of-N).
384
+ * Sent as `body.gateway` to the Router.
385
+ */
386
+ gateway?: GatewayOptions;
387
+ /**
388
+ * Provider-specific parameters passed through to the upstream API.
389
+ * These are spread into the request body alongside standard fields.
390
+ * Example: `{ thinking: { type: 'enabled', budget_tokens: 8000 } }`
391
+ */
392
+ providerOptions?: Record<string, unknown>;
393
+ /**
394
+ * Route this call through the Tangle Router's cli-bridge short-circuit.
395
+ * See {@link BridgeOptions}. When set, `model` is rewritten to
396
+ * `bridge/<harness>/<model>` and bridge headers are injected.
397
+ */
398
+ bridge?: BridgeOptions;
399
+ }
400
+ interface ChatCompletion {
401
+ id: string;
402
+ object: string;
403
+ created: number;
404
+ model: string;
405
+ choices: {
406
+ index: number;
407
+ message: ChatMessage;
408
+ finish_reason: string;
409
+ }[];
410
+ usage?: {
411
+ prompt_tokens: number;
412
+ completion_tokens: number;
413
+ total_tokens: number;
414
+ };
415
+ }
416
+ interface ChatCompletionChunk {
417
+ id: string;
418
+ object: string;
419
+ created: number;
420
+ model: string;
421
+ choices: {
422
+ index: number;
423
+ delta: Partial<ChatMessage>;
424
+ finish_reason: string | null;
425
+ }[];
426
+ }
427
+ interface Model {
428
+ id: string;
429
+ name: string;
430
+ description?: string;
431
+ context_length: number;
432
+ pricing: {
433
+ prompt: string;
434
+ completion: string;
435
+ };
436
+ _provider?: string;
437
+ architecture?: {
438
+ input_modalities?: string[];
439
+ output_modalities?: string[];
440
+ };
441
+ }
442
+ interface Operator {
443
+ id: string;
444
+ slug: string;
445
+ name: string;
446
+ description?: string;
447
+ status: string;
448
+ endpointUrl: string;
449
+ blueprintType: string;
450
+ reputationScore: number;
451
+ uptimePercent: number;
452
+ avgLatencyMs: number;
453
+ totalRequests: number;
454
+ stakeTnt: number;
455
+ /** GPU model name (e.g. "A100", "H100") */
456
+ gpuModel?: string;
457
+ /** Number of GPUs available */
458
+ gpuCount?: number;
459
+ /** Total VRAM across all GPUs in MiB */
460
+ totalVramMib?: number;
461
+ /** Whether this operator is TEE-attested */
462
+ teeAttested?: boolean;
463
+ /** TEE provider if attested (e.g. "aws_nitro") */
464
+ teeProvider?: string;
465
+ models: {
466
+ modelId: string;
467
+ inputPrice: number;
468
+ outputPrice: number;
469
+ }[];
470
+ }
471
+ interface CreditBalance {
472
+ balance: number;
473
+ transactions: {
474
+ id: string;
475
+ amount: number;
476
+ type: string;
477
+ description: string;
478
+ createdAt: string;
479
+ }[];
480
+ }
481
+ interface CreateKeyOptions {
482
+ name: string;
483
+ /** Explicit parent key ID. When omitted and calling with an API key,
484
+ * the new key is auto-parented to the calling key. */
485
+ parentKeyId?: string;
486
+ product?: 'router' | 'sandbox' | 'evals' | 'blueprint-agent';
487
+ projectId?: string;
488
+ budgetUsd?: number;
489
+ allowedModels?: string[];
490
+ rpmLimit?: number;
491
+ /** ISO 8601 datetime. Must be in the future. */
492
+ expiresAt?: string;
493
+ }
494
+ interface CreatedKey {
495
+ id: string;
496
+ key: string;
497
+ prefix: string;
498
+ name: string;
499
+ product: string | null;
500
+ budgetUsd: number | null;
501
+ budgetRemaining: number | null;
502
+ }
503
+ interface ApiKeyInfo {
504
+ id: string;
505
+ keyPrefix: string;
506
+ name: string;
507
+ parentKeyId: string | null;
508
+ product: string | null;
509
+ projectId: string | null;
510
+ budgetUsd: number | null;
511
+ budgetSpent: number;
512
+ allowedModels: string[] | null;
513
+ rpmLimit: number | null;
514
+ expiresAt: string | null;
515
+ lastUsedAt: string | null;
516
+ revokedAt: string | null;
517
+ createdAt: string;
518
+ }
519
+ interface UpdateKeyOptions {
520
+ name?: string;
521
+ budgetUsd?: number;
522
+ allowedModels?: string[];
523
+ rpmLimit?: number | null;
524
+ expiresAt?: string | null;
525
+ }
526
+ /** Status event from an async job SSE stream */
527
+ interface JobEvent {
528
+ status: 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled';
529
+ progress?: number;
530
+ result?: Record<string, unknown>;
531
+ error?: string;
532
+ timestamp: number;
533
+ }
534
+ /** Options for watchJob() */
535
+ interface WatchJobOptions {
536
+ /** Operator endpoint URL (if not using default routing) */
537
+ operatorUrl?: string;
538
+ /** Callback for each event (useful for progress tracking) */
539
+ onEvent?: (event: JobEvent) => void;
540
+ /** Timeout in ms (default: 5 minutes) */
541
+ timeout?: number;
542
+ /** Model to route to (for operator discovery) */
543
+ model?: string;
544
+ /** SSE bearer token (replaces API key for operator SSE auth) */
545
+ sseToken?: string;
546
+ }
547
+ interface SpendAuth {
548
+ commitment: string;
549
+ serviceId: string;
550
+ jobIndex: number;
551
+ amount: string;
552
+ operator: string;
553
+ nonce: string;
554
+ expiry: string;
555
+ signature: string;
556
+ }
557
+
558
+ /**
559
+ * Private Router — operator rotation strategies for privacy-preserving inference.
560
+ *
561
+ * Each strategy determines how requests are distributed across operators
562
+ * to minimize the information any single operator can gather about a user's
563
+ * conversation patterns.
564
+ */
565
+ interface OperatorInfo {
566
+ slug: string;
567
+ endpointUrl: string;
568
+ region: string;
569
+ reputationScore: number;
570
+ avgLatencyMs: number;
571
+ models: string[];
572
+ }
573
+ type RoutingStrategy = 'round-robin' | 'random' | 'geo-distributed' | 'min-exposure' | 'latency-aware';
574
+ interface PrivateRouterConfig {
575
+ strategy: RoutingStrategy;
576
+ /** Max requests to same operator before forced rotation */
577
+ maxRequestsPerOperator: number;
578
+ /** Minimum number of distinct operators to use */
579
+ minOperators: number;
580
+ /** Region preferences (operators in these regions preferred) */
581
+ preferRegions?: string[];
582
+ /** Exclude specific operators */
583
+ excludeOperators?: string[];
584
+ /** Enable context summarization between operator switches (reduces info leakage) */
585
+ summarizeOnSwitch: boolean;
586
+ }
587
+ declare class PrivateRouter {
588
+ private config;
589
+ private operators;
590
+ private usage;
591
+ private currentIndex;
592
+ private totalRequests;
593
+ constructor(config?: Partial<PrivateRouterConfig>);
594
+ /** Set the available operator pool */
595
+ setOperators(operators: OperatorInfo[]): void;
596
+ /** Select the next operator for a request */
597
+ selectOperator(model: string): OperatorInfo | null;
598
+ /** Should we summarize context before this request? (operator is changing) */
599
+ shouldSummarize(model: string): boolean;
600
+ /** Get privacy stats */
601
+ getStats(): {
602
+ totalRequests: number;
603
+ operatorsUsed: number;
604
+ operatorBreakdown: {
605
+ slug: string;
606
+ requests: number;
607
+ lastUsed: number;
608
+ }[];
609
+ strategy: RoutingStrategy;
610
+ };
611
+ private roundRobin;
612
+ private random;
613
+ private geoDistributed;
614
+ private minExposure;
615
+ private latencyAware;
616
+ private recordUsage;
617
+ private getLastUsedOperator;
618
+ private peekNextOperator;
619
+ }
620
+
621
+ /**
622
+ * Core HTTP client for Tangle AI Cloud.
623
+ * Shared between CLI and SDK.
624
+ */
625
+
626
+ declare class TCloudClient {
627
+ readonly baseURL: string;
628
+ readonly platformURL: string;
629
+ readonly apiKey?: string;
630
+ readonly model: string;
631
+ private headers;
632
+ private spendAuthFn?;
633
+ private privacy?;
634
+ private limits?;
635
+ private retryConfig;
636
+ private timeoutMs;
637
+ private _totalSpent;
638
+ private _requestCount;
639
+ readonly privateRouter?: PrivateRouter;
640
+ private _cachedOperators;
641
+ private _operatorsCachedAt;
642
+ private static readonly OPERATORS_TTL_MS;
643
+ constructor(config?: TCloudConfig);
644
+ /** Set the SpendAuth signer for private mode */
645
+ setSpendAuthSigner(fn: () => Promise<SpendAuth>): void;
646
+ /** Current metering stats */
647
+ get usage(): {
648
+ totalSpent: number;
649
+ requestCount: number;
650
+ limits: {
651
+ maxCostPerRequest?: number;
652
+ maxTotalSpend?: number;
653
+ maxRequests?: number;
654
+ onLimitWarning?: (info: {
655
+ type: "cost" | "total" | "requests";
656
+ current: number;
657
+ limit: number;
658
+ }) => void;
659
+ onLimitReached?: (info: {
660
+ type: "cost" | "total" | "requests";
661
+ current: number;
662
+ limit: number;
663
+ }) => void;
664
+ } | undefined;
665
+ };
666
+ /** Check spending limits before a request. Throws TCloudError if blocked. */
667
+ private checkLimits;
668
+ /** Ensure the private router has operators loaded (with TTL-based caching) */
669
+ private ensureRouterOperators;
670
+ /** Track cost after a response, using actual pricing from response headers when available */
671
+ private trackCost;
672
+ /**
673
+ * Core fetch with retry + timeout. All helpers build on this.
674
+ * Retries on retryable status codes with exponential backoff + jitter.
675
+ */
676
+ private _doFetch;
677
+ /**
678
+ * Shared request helper for billable JSON API calls.
679
+ * Enforces: checkLimits → fetch with retry/timeout → error parsing → requestCount.
680
+ */
681
+ private _request;
682
+ /**
683
+ * Shared request helper for read-only/non-billable JSON API calls.
684
+ * No limits check, no request counting.
685
+ */
686
+ private _fetch;
687
+ /**
688
+ * Shared request helper for billable calls that return non-JSON (e.g. ArrayBuffer).
689
+ */
690
+ private _requestRaw;
691
+ /**
692
+ * Prepare headers for chat requests — operator routing + SpendAuth +
693
+ * bridge short-circuit headers when `options.bridge` is set.
694
+ * Shared between chat() and chatStream() to eliminate duplication.
695
+ */
696
+ private _prepareChatRequest;
697
+ /**
698
+ * Resolve the effective model string. When a bridge is set, rewrite to
699
+ * `bridge/<harness>/<model>` (or `bridge/<harness>` if no model).
700
+ */
701
+ private _effectiveModel;
702
+ /** Build the chat completions request body */
703
+ private _chatBody;
704
+ /** Chat completion (non-streaming) */
705
+ chat(options: ChatOptions): Promise<ChatCompletion>;
706
+ /** Chat completion (streaming) — returns an async iterator of chunks */
707
+ chatStream(options: ChatOptions): AsyncGenerator<ChatCompletionChunk>;
708
+ /**
709
+ * Bridge — scoped helper for a subscription-backed CLI harness behind
710
+ * the Tangle Router's cli-bridge. Returns a mini-client bound to
711
+ * (harness, unlock, resume) so you don't thread those through every
712
+ * call.
713
+ *
714
+ * ```ts
715
+ * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
716
+ * await kimi.ask('review this diff…')
717
+ * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
718
+ * ```
719
+ *
720
+ * Sessions persist across process restarts — use the same `resume` id
721
+ * to land on the same CLI conversation (context intact, no replay tax).
722
+ */
723
+ bridge(cfg: BridgeOptions): BridgeSession;
724
+ /** Convenience: send a single message and get the text response */
725
+ ask(message: string, modelOrOptions?: string | Partial<ChatOptions>): Promise<string>;
726
+ /** Convenience: send a single message and get the full completion (with usage) */
727
+ askFull(message: string, modelOrOptions?: string | Partial<ChatOptions>): Promise<ChatCompletion>;
728
+ /** Convenience: stream a single message and yield text chunks */
729
+ askStream(message: string, modelOrOptions?: string | Partial<ChatOptions>): AsyncGenerator<string>;
730
+ /** List available models */
731
+ models(): Promise<Model[]>;
732
+ /** List active operators */
733
+ operators(): Promise<{
734
+ operators: Operator[];
735
+ stats: any;
736
+ }>;
737
+ /** Get credit balance */
738
+ credits(): Promise<CreditBalance>;
739
+ /** Add credits via Stripe checkout. Returns the checkout URL. */
740
+ addCredits(amount: number): Promise<{
741
+ url: string;
742
+ }>;
743
+ /** Get transaction history */
744
+ transactions(limit?: number): Promise<{
745
+ id: string;
746
+ amount: number;
747
+ type: string;
748
+ product: string | null;
749
+ description: string | null;
750
+ createdAt: string;
751
+ }[]>;
752
+ /**
753
+ * Create a new API key.
754
+ * When called with an API key (not session), the new key is automatically
755
+ * a child of the calling key — enabling hierarchical key delegation.
756
+ *
757
+ * Pass `parentKeyId` explicitly to create a child of a specific key.
758
+ * Child keys inherit the parent's product scope, allowedModels, and rpmLimit
759
+ * if not specified. Budget cannot exceed the parent's remaining budget.
760
+ */
761
+ createKey(opts: CreateKeyOptions): Promise<CreatedKey>;
762
+ /** Get a single API key by ID */
763
+ getKey(id: string): Promise<ApiKeyInfo>;
764
+ /**
765
+ * List API keys.
766
+ * Pass `children: true` to list child keys of the calling API key.
767
+ */
768
+ keys(opts?: {
769
+ children?: boolean;
770
+ }): Promise<ApiKeyInfo[]>;
771
+ /**
772
+ * Update an API key's limits.
773
+ * Can adjust budget, allowedModels, rpmLimit, expiresAt, and name.
774
+ */
775
+ updateKey(id: string, updates: UpdateKeyOptions): Promise<ApiKeyInfo>;
776
+ /** Revoke an API key. If the key has children, they are also revoked recursively. */
777
+ revokeKey(id: string): Promise<void>;
778
+ /** Rotate an API key — creates new key with same config, revokes old */
779
+ rotateKey(id: string): Promise<{
780
+ newKey: CreatedKey;
781
+ revokedKeyId: string;
782
+ }>;
783
+ /** Create a project for usage attribution */
784
+ createProject(name: string, product?: string): Promise<{
785
+ id: string;
786
+ name: string;
787
+ }>;
788
+ /** List projects */
789
+ projects(): Promise<{
790
+ id: string;
791
+ name: string;
792
+ product: string | null;
793
+ createdAt: string;
794
+ }[]>;
795
+ /** Generate embeddings */
796
+ embeddings(options: EmbeddingOptions): Promise<EmbeddingResponse>;
797
+ /** Generate images */
798
+ imageGenerate(options: ImageGenerateOptions): Promise<ImageResponse>;
799
+ /** Rerank documents by relevance to a query */
800
+ rerank(options: RerankOptions): Promise<RerankResponse>;
801
+ /** Text-to-speech */
802
+ speech(options: {
803
+ model?: string;
804
+ input: string;
805
+ voice?: string;
806
+ }): Promise<ArrayBuffer>;
807
+ /** Legacy completions endpoint */
808
+ completions(options: CompletionOptions): Promise<CompletionResponse>;
809
+ /** Audio transcription (speech-to-text) */
810
+ transcribe(file: Blob, options?: {
811
+ model?: string;
812
+ language?: string;
813
+ prompt?: string;
814
+ }): Promise<TranscriptionResponse>;
815
+ /** Create a fine-tuning job */
816
+ fineTuneCreate(options: FineTuningJobOptions): Promise<FineTuningJob>;
817
+ /** List fine-tuning jobs */
818
+ fineTuneList(): Promise<{
819
+ data: FineTuningJob[];
820
+ }>;
821
+ /** Submit a batch of chat requests */
822
+ batch(requests: BatchRequest[]): Promise<BatchJobResponse>;
823
+ /** Get batch job status */
824
+ batchStatus(jobId: string): Promise<BatchJobResponse>;
825
+ /** Generate video */
826
+ videoGenerate(options: VideoGenerateOptions): Promise<VideoResponse>;
827
+ /** Get video generation status */
828
+ videoStatus(id: string): Promise<VideoResponse>;
829
+ /** Generate an avatar video (lip-synced talking head from audio + face image).
830
+ * Returns 202 with a job_id for async polling via avatarJobStatus(). */
831
+ avatarGenerate(options: AvatarGenerateRequest): Promise<AvatarGenerateResponse>;
832
+ /** Poll an avatar generation job by ID. */
833
+ avatarJobStatus(jobId: string): Promise<AvatarJobStatus>;
834
+ /** Poll an avatar job until it reaches a terminal state (completed/failed).
835
+ * Returns the final job status. Throws on failure. */
836
+ pollAvatarJob(jobId: string, options?: {
837
+ intervalMs?: number;
838
+ timeoutMs?: number;
839
+ }): Promise<AvatarJobStatus>;
840
+ /**
841
+ * Watch an async job via SSE until it reaches a terminal state.
842
+ * Works with avatar, video, and training blueprint operators.
843
+ *
844
+ * @param jobId - The job ID returned by the creation endpoint
845
+ * @param options - Optional: operatorUrl override, onEvent callback
846
+ * @returns The final JobEvent (completed/failed/cancelled)
847
+ */
848
+ watchJob(jobId: string, options?: WatchJobOptions): Promise<JobEvent>;
849
+ /** Create a vector collection on the operator's vector store */
850
+ createCollection(options: {
851
+ name: string;
852
+ dimensions: number;
853
+ distance_metric?: string;
854
+ }): Promise<any>;
855
+ /** List collections on the operator's vector store */
856
+ listCollections(): Promise<any>;
857
+ /** Upsert vectors into a collection */
858
+ upsertVectors(collection: string, vectors: Array<{
859
+ id: string;
860
+ vector: number[];
861
+ metadata?: Record<string, any>;
862
+ }>): Promise<any>;
863
+ /** Similarity search in a collection */
864
+ queryVectors(collection: string, options: {
865
+ vector: number[];
866
+ top_k?: number;
867
+ filter?: Record<string, any>;
868
+ }): Promise<any>;
869
+ /** RAG query — embed text + search collection in one call */
870
+ ragQuery(options: {
871
+ query: string;
872
+ collection: string;
873
+ top_k?: number;
874
+ embedding_model?: string;
875
+ }): Promise<any>;
876
+ /** Search models by name, provider, or capability */
877
+ searchModels(query: string): Promise<Model[]>;
878
+ /** Estimate cost for a request (without sending it) */
879
+ estimateCost(options: {
880
+ model?: string;
881
+ inputTokens: number;
882
+ outputTokens: number;
883
+ }): Promise<{
884
+ inputCost: number;
885
+ outputCost: number;
886
+ total: number;
887
+ }>;
888
+ /**
889
+ * Get a pricing spectrum across resource tiers for a model.
890
+ *
891
+ * Uses REAL per-operator pricing from `operator.models[].inputPrice`.
892
+ * Each tier filters operators by GPU count and TEE capability, then
893
+ * reports the cheapest and most expensive operator for that config.
894
+ *
895
+ * @param options.model - Model ID to price (falls back to client default)
896
+ * @param options.tiers - Number of tiers (1-7, default 5)
897
+ */
898
+ pricingSpectrum(options: {
899
+ model?: string;
900
+ tiers?: number;
901
+ }): Promise<PricingTier[]>;
902
+ private get _apiRoot();
903
+ eval(opts: {
904
+ models: string[];
905
+ scenarios: Array<{
906
+ id: string;
907
+ prompt: string;
908
+ rubric?: string;
909
+ category?: string;
910
+ expectedContains?: string[];
911
+ maxLatencyMs?: number;
912
+ }>;
913
+ judge?: string;
914
+ iterations?: number;
915
+ systemPrompt?: string;
916
+ }): Promise<{
917
+ results: Array<{
918
+ model: string;
919
+ summary: any;
920
+ scenarios: any[];
921
+ }>;
922
+ }>;
923
+ createSuite(opts: {
924
+ name: string;
925
+ scenarios: Array<{
926
+ id: string;
927
+ prompt: string;
928
+ rubric?: string;
929
+ }>;
930
+ models: string[];
931
+ judge?: string;
932
+ iterations?: number;
933
+ tags?: string[];
934
+ }): Promise<{
935
+ suite: {
936
+ id: string;
937
+ name: string;
938
+ };
939
+ }>;
940
+ listSuites(): Promise<{
941
+ suites: Array<{
942
+ id: string;
943
+ name: string;
944
+ models: string[];
945
+ }>;
946
+ }>;
947
+ runSuite(suiteId: string, opts?: {
948
+ baseline?: boolean;
949
+ concurrency?: number;
950
+ }): Promise<any>;
951
+ listRuns(suiteId: string): Promise<any>;
952
+ getRun(runId: string): Promise<any>;
953
+ setBaseline(runId: string): Promise<void>;
954
+ sandboxPricing(opts?: {
955
+ cpu?: number;
956
+ ram?: number;
957
+ disk?: number;
958
+ }): Promise<{
959
+ pricing: {
960
+ hourlyRate: number;
961
+ perMinuteRate: number;
962
+ };
963
+ plan: string;
964
+ limits: {
965
+ maxCpu: number;
966
+ maxRamGb: number;
967
+ maxDiskGb: number;
968
+ };
969
+ balance: number;
970
+ canAfford: {
971
+ minutes: number;
972
+ hours: number;
973
+ };
974
+ }>;
975
+ sandboxStatus(): Promise<{
976
+ linked: boolean;
977
+ keyPrefix?: string;
978
+ gatewayUrl?: string;
979
+ }>;
980
+ sandboxProvision(): Promise<{
981
+ provisioned: boolean;
982
+ minutesRemaining?: number;
983
+ }>;
984
+ sandboxCreate(opts: {
985
+ model?: string;
986
+ harness?: 'claude-code' | 'codex' | 'opencode' | 'amp' | 'factory';
987
+ cpu?: number;
988
+ ram?: number;
989
+ storage?: number;
990
+ gitUrl?: string;
991
+ systemPrompt?: string;
992
+ }): Promise<{
993
+ sessionId: string;
994
+ harness: string;
995
+ model: string;
996
+ minutesRemaining?: number;
997
+ }>;
998
+ sandboxList(): Promise<{
999
+ sessions: Array<{
1000
+ id: string;
1001
+ status: string;
1002
+ model: string;
1003
+ harness: string;
1004
+ }>;
1005
+ }>;
1006
+ sandboxStats(sandboxId: string): Promise<{
1007
+ config: {
1008
+ cpu: number;
1009
+ ramGb: number;
1010
+ diskGb: number;
1011
+ };
1012
+ uptime: number;
1013
+ computeMinutes: number;
1014
+ live?: {
1015
+ cpuPercent: number;
1016
+ memoryUsedMb: number;
1017
+ memoryTotalMb: number;
1018
+ };
1019
+ }>;
1020
+ sandboxDestroy(sessionId: string): Promise<{
1021
+ deleted: boolean;
1022
+ }>;
1023
+ userInfo(): Promise<{
1024
+ user: {
1025
+ id: string;
1026
+ email: string;
1027
+ name?: string;
1028
+ };
1029
+ balance: number;
1030
+ subscription: {
1031
+ plan: string;
1032
+ status: string;
1033
+ } | null;
1034
+ usage: Record<string, {
1035
+ cost: number;
1036
+ count: number;
1037
+ }>;
1038
+ }>;
1039
+ }
1040
+ /** Select N evenly-spaced items, always including first and last. */
1041
+ /**
1042
+ * BridgeSession — a chat client scoped to one bridge configuration.
1043
+ *
1044
+ * Instead of threading `{ harness, unlock, resume }` through every
1045
+ * `chat()` call, create a session once and call `ask` / `stream` / `chat`
1046
+ * on it. The session's `resume` id is stable across calls so follow-up
1047
+ * turns land on the same CLI conversation.
1048
+ *
1049
+ * ```ts
1050
+ * const tcloud = new TCloudClient({ apiKey, baseURL: 'https://router.tangle.tools/api' })
1051
+ * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
1052
+ *
1053
+ * // one-shot
1054
+ * const reply = await kimi.ask('summarize this diff')
1055
+ *
1056
+ * // streaming
1057
+ * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
1058
+ *
1059
+ * // full OpenAI-shaped request
1060
+ * const completion = await kimi.chat({ messages, temperature: 0.2 })
1061
+ *
1062
+ * // new resume id for a different logical conversation
1063
+ * const kimiOther = kimi.withResume('ticket-123')
1064
+ * ```
1065
+ */
1066
+ declare class BridgeSession {
1067
+ private readonly client;
1068
+ private readonly cfg;
1069
+ constructor(client: TCloudClient, cfg: BridgeOptions);
1070
+ /** Full chat completion (non-streaming). */
1071
+ chat(options: Omit<ChatOptions, 'bridge'>): Promise<ChatCompletion>;
1072
+ /** Stream OpenAI chat.completion.chunks. */
1073
+ chatStream(options: Omit<ChatOptions, 'bridge'>): AsyncGenerator<ChatCompletionChunk>;
1074
+ /** One-shot: send a string, get the assistant text. */
1075
+ ask(message: string, extra?: Omit<Partial<ChatOptions>, 'bridge' | 'messages'>): Promise<string>;
1076
+ /** One-shot: send a string, stream text deltas. */
1077
+ stream(message: string, extra?: Omit<Partial<ChatOptions>, 'bridge' | 'messages'>): AsyncGenerator<string>;
1078
+ /** Turn-based: send full message history, get assistant text. */
1079
+ turn(messages: ChatMessage[], extra?: Omit<Partial<ChatOptions>, 'bridge' | 'messages'>): Promise<string>;
1080
+ /** Clone with a new resume id — same harness, different logical conversation. */
1081
+ withResume(resume: string): BridgeSession;
1082
+ /** Clone with a different model inside the same harness. */
1083
+ withModel(model: string): BridgeSession;
1084
+ /** The effective model id that will land on the router (`bridge/<harness>/<model>`). */
1085
+ get model(): string;
1086
+ /** The resume id currently bound to this session, if any. */
1087
+ get resume(): string | undefined;
1088
+ }
1089
+ interface TierConfig {
1090
+ name: string;
1091
+ cpu: number;
1092
+ ramGb: number;
1093
+ gpu: number;
1094
+ tee: boolean;
1095
+ }
1096
+ interface PricingTier {
1097
+ tier: string;
1098
+ config: TierConfig;
1099
+ /** Raw cheapest per-input-token price (for programmatic use) */
1100
+ cheapestPrice?: number;
1101
+ /** Raw priciest per-input-token price (undefined if same as cheapest) */
1102
+ priciestPrice?: number;
1103
+ /** Formatted cheapest price */
1104
+ cheapest: string;
1105
+ /** Formatted priciest price (undefined if only one price point) */
1106
+ priciest?: string;
1107
+ /** Operators matching GPU/TEE requirements */
1108
+ availableOperators: number;
1109
+ /** Operators that also serve the requested model at a listed price */
1110
+ operatorsWithModel: number;
1111
+ }
1112
+ declare class TCloudError extends Error {
1113
+ status: number;
1114
+ constructor(status: number, message: string);
1115
+ }
1116
+
1117
+ export { type ApiKeyInfo as A, type BatchJobResponse as B, type ChatCompletion as C, type RoutingStrategy as D, type EmbeddingOptions as E, type FineTuningJob as F, type GatewayOptions as G, type SpendAuth as H, type ImageGenerateOptions as I, type JobEvent as J, type SpendingLimits as K, TCloudError as L, type Model as M, type TierConfig as N, type Operator as O, type PricingTier as P, type TranscriptionResponse as Q, type RerankOptions as R, type ShieldedConfig as S, TCloudClient as T, type UpdateKeyOptions as U, type VideoGenerateOptions as V, type VideoResponse as W, type WatchJobOptions as X, type TCloudConfig as a, type AvatarGenerateRequest as b, type AvatarGenerateResponse as c, type AvatarJobStatus as d, type AvatarResult as e, type BatchRequest as f, type BridgeOptions as g, BridgeSession as h, type ChatCompletionChunk as i, type ChatMessage as j, type ChatOptions as k, type CompletionOptions as l, type CompletionResponse as m, type CreateKeyOptions as n, type CreatedKey as o, type CreditBalance as p, type EmbeddingResponse as q, type FineTuningJobOptions as r, type ImageResponse as s, type OperatorInfo as t, type PrivacyConfig as u, PrivateRouter as v, type PrivateRouterConfig as w, type RerankResponse as x, type RetryConfig as y, type RoutingConfig as z };