@tangle-network/tcloud 0.2.0 → 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.
@@ -2,6 +2,8 @@
2
2
  interface TCloudConfig {
3
3
  /** API base URL (default: https://router.tangle.tools/v1) */
4
4
  baseURL?: string;
5
+ /** Platform API URL for billing/keys (default: https://id.tangle.tools) */
6
+ platformURL?: string;
5
7
  /** API key for standard (non-private) mode */
6
8
  apiKey?: string;
7
9
  /** Default model */
@@ -260,6 +262,91 @@ interface ChatMessage {
260
262
  content: string;
261
263
  name?: string;
262
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
+ }
263
350
  interface ChatOptions {
264
351
  /** Model to use */
265
352
  model?: string;
@@ -292,12 +379,23 @@ interface ChatOptions {
292
379
  name: string;
293
380
  };
294
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;
295
387
  /**
296
388
  * Provider-specific parameters passed through to the upstream API.
297
389
  * These are spread into the request body alongside standard fields.
298
390
  * Example: `{ thinking: { type: 'enabled', budget_tokens: 8000 } }`
299
391
  */
300
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;
301
399
  }
302
400
  interface ChatCompletion {
303
401
  id: string;
@@ -380,6 +478,51 @@ interface CreditBalance {
380
478
  createdAt: string;
381
479
  }[];
382
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
+ }
383
526
  /** Status event from an async job SSE stream */
384
527
  interface JobEvent {
385
528
  status: 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled';
@@ -482,6 +625,7 @@ declare class PrivateRouter {
482
625
 
483
626
  declare class TCloudClient {
484
627
  readonly baseURL: string;
628
+ readonly platformURL: string;
485
629
  readonly apiKey?: string;
486
630
  readonly model: string;
487
631
  private headers;
@@ -545,16 +689,38 @@ declare class TCloudClient {
545
689
  */
546
690
  private _requestRaw;
547
691
  /**
548
- * Prepare headers for chat requests — operator routing + SpendAuth.
692
+ * Prepare headers for chat requests — operator routing + SpendAuth +
693
+ * bridge short-circuit headers when `options.bridge` is set.
549
694
  * Shared between chat() and chatStream() to eliminate duplication.
550
695
  */
551
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;
552
702
  /** Build the chat completions request body */
553
703
  private _chatBody;
554
704
  /** Chat completion (non-streaming) */
555
705
  chat(options: ChatOptions): Promise<ChatCompletion>;
556
706
  /** Chat completion (streaming) — returns an async iterator of chunks */
557
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;
558
724
  /** Convenience: send a single message and get the text response */
559
725
  ask(message: string, modelOrOptions?: string | Partial<ChatOptions>): Promise<string>;
560
726
  /** Convenience: send a single message and get the full completion (with usage) */
@@ -570,25 +736,62 @@ declare class TCloudClient {
570
736
  }>;
571
737
  /** Get credit balance */
572
738
  credits(): Promise<CreditBalance>;
573
- /** Add credits */
739
+ /** Add credits via Stripe checkout. Returns the checkout URL. */
574
740
  addCredits(amount: number): Promise<{
575
- balance: number;
741
+ url: string;
576
742
  }>;
577
- /** Create a new API key */
578
- createKey(name: string): Promise<{
579
- key: string;
743
+ /** Get transaction history */
744
+ transactions(limit?: number): Promise<{
580
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;
581
787
  }>;
582
- /** List API keys */
583
- keys(): Promise<{
788
+ /** List projects */
789
+ projects(): Promise<{
584
790
  id: string;
585
791
  name: string;
586
- prefix: string;
792
+ product: string | null;
587
793
  createdAt: string;
588
- lastUsedAt: string | null;
589
794
  }[]>;
590
- /** Revoke an API key */
591
- revokeKey(id: string): Promise<void>;
592
795
  /** Generate embeddings */
593
796
  embeddings(options: EmbeddingOptions): Promise<EmbeddingResponse>;
594
797
  /** Generate images */
@@ -696,6 +899,192 @@ declare class TCloudClient {
696
899
  model?: string;
697
900
  tiers?: number;
698
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;
699
1088
  }
700
1089
  interface TierConfig {
701
1090
  name: string;
@@ -725,4 +1114,4 @@ declare class TCloudError extends Error {
725
1114
  constructor(status: number, message: string);
726
1115
  }
727
1116
 
728
- export { type AvatarGenerateRequest as A, type BatchJobResponse as B, type ChatCompletion as C, type TranscriptionResponse as D, type EmbeddingOptions as E, type FineTuningJob as F, type VideoResponse as G, type ImageGenerateOptions as I, type JobEvent as J, type Model as M, type Operator as O, type PricingTier as P, type RerankOptions as R, type ShieldedConfig as S, TCloudClient as T, type VideoGenerateOptions as V, type WatchJobOptions as W, type TCloudConfig as a, type AvatarGenerateResponse as b, type AvatarJobStatus as c, type AvatarResult as d, type BatchRequest as e, type ChatCompletionChunk as f, type ChatMessage as g, type ChatOptions as h, type CompletionOptions as i, type CompletionResponse as j, type CreditBalance as k, type EmbeddingResponse as l, type FineTuningJobOptions as m, type ImageResponse as n, type OperatorInfo as o, type PrivacyConfig as p, PrivateRouter as q, type PrivateRouterConfig as r, type RerankResponse as s, type RetryConfig as t, type RoutingConfig as u, type RoutingStrategy as v, type SpendAuth as w, type SpendingLimits as x, TCloudError as y, type TierConfig as z };
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 };