@tangle-network/tcloud 0.1.2 → 0.1.4

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.
@@ -60,14 +60,23 @@ var TCloudClient = class {
60
60
  this.limits = config.limits;
61
61
  this.headers = {
62
62
  "Content-Type": "application/json",
63
- "X-Tangle-Client": "tcloud-sdk/0.1.0"
63
+ "X-Tangle-Client": "tcloud-sdk/0.1.4"
64
64
  };
65
65
  if (this.apiKey) {
66
66
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
67
67
  }
68
+ if (config.routing?.mode) {
69
+ this.headers["X-Tangle-Routing"] = config.routing.mode;
70
+ }
68
71
  if (config.routing?.prefer) {
69
72
  this.headers["X-Tangle-Operator"] = config.routing.prefer;
70
73
  }
74
+ if (config.routing?.blueprintId) {
75
+ this.headers["X-Tangle-Blueprint"] = config.routing.blueprintId;
76
+ }
77
+ if (config.routing?.serviceId) {
78
+ this.headers["X-Tangle-Service"] = config.routing.serviceId;
79
+ }
71
80
  if (config.routing?.region) {
72
81
  this.headers["X-Tangle-Region"] = config.routing.region;
73
82
  }
@@ -104,12 +113,19 @@ var TCloudClient = class {
104
113
  if (pct >= 0.8) this.limits.onLimitWarning({ type: "total", current: this._totalSpent, limit: this.limits.maxTotalSpend });
105
114
  }
106
115
  }
107
- /** Track cost after a response */
108
- trackCost(completion) {
116
+ /** Track cost after a response, using actual pricing from response headers when available */
117
+ trackCost(completion, res) {
109
118
  this._requestCount++;
110
119
  if (completion.usage) {
111
- const tokens = completion.usage.total_tokens || 0;
112
- const estimatedCost = tokens * 1e-6;
120
+ let estimatedCost;
121
+ const inputPrice = res ? parseFloat(res.headers.get("x-tangle-price-input") || "0") : 0;
122
+ const outputPrice = res ? parseFloat(res.headers.get("x-tangle-price-output") || "0") : 0;
123
+ if (inputPrice > 0 || outputPrice > 0) {
124
+ estimatedCost = (completion.usage.prompt_tokens || 0) * inputPrice + (completion.usage.completion_tokens || 0) * outputPrice;
125
+ } else {
126
+ const tokens = completion.usage.total_tokens || 0;
127
+ estimatedCost = tokens * 1e-6;
128
+ }
113
129
  this._totalSpent += estimatedCost;
114
130
  if (this.limits?.maxCostPerRequest && estimatedCost > this.limits.maxCostPerRequest) {
115
131
  this.limits.onLimitReached?.({ type: "cost", current: estimatedCost, limit: this.limits.maxCostPerRequest });
@@ -147,7 +163,7 @@ var TCloudClient = class {
147
163
  throw new TCloudError(res.status, err.error?.message || err.error || err.message || res.statusText);
148
164
  }
149
165
  const completion = await res.json();
150
- this.trackCost(completion);
166
+ this.trackCost(completion, res);
151
167
  return completion;
152
168
  }
153
169
  /** Chat completion (streaming) — returns an async iterator of chunks */
@@ -286,6 +302,188 @@ var TCloudClient = class {
286
302
  }, false);
287
303
  if (!res.ok) throw new TCloudError(res.status, "Failed to revoke key");
288
304
  }
305
+ /** Generate embeddings */
306
+ async embeddings(options) {
307
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/embeddings`, {
308
+ method: "POST",
309
+ headers: this.headers,
310
+ body: JSON.stringify({
311
+ model: options.model || "text-embedding-3-small",
312
+ input: options.input
313
+ })
314
+ }, false);
315
+ if (!res.ok) {
316
+ const err = await res.json().catch(() => ({ error: res.statusText }));
317
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
318
+ }
319
+ this._requestCount++;
320
+ return res.json();
321
+ }
322
+ /** Generate images */
323
+ async imageGenerate(options) {
324
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/images/generations`, {
325
+ method: "POST",
326
+ headers: this.headers,
327
+ body: JSON.stringify({
328
+ model: options.model || "dall-e-3",
329
+ prompt: options.prompt,
330
+ n: options.n,
331
+ size: options.size,
332
+ quality: options.quality,
333
+ response_format: options.response_format
334
+ })
335
+ }, false);
336
+ if (!res.ok) {
337
+ const err = await res.json().catch(() => ({ error: res.statusText }));
338
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
339
+ }
340
+ this._requestCount++;
341
+ return res.json();
342
+ }
343
+ /** Rerank documents by relevance to a query */
344
+ async rerank(options) {
345
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/rerank`, {
346
+ method: "POST",
347
+ headers: this.headers,
348
+ body: JSON.stringify({
349
+ model: options.model || "rerank-english-v3.0",
350
+ query: options.query,
351
+ documents: options.documents,
352
+ top_n: options.top_n
353
+ })
354
+ }, false);
355
+ if (!res.ok) {
356
+ const err = await res.json().catch(() => ({ error: res.statusText }));
357
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
358
+ }
359
+ this._requestCount++;
360
+ return res.json();
361
+ }
362
+ /** Text-to-speech */
363
+ async speech(options) {
364
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/speech`, {
365
+ method: "POST",
366
+ headers: this.headers,
367
+ body: JSON.stringify({
368
+ model: options.model || "tts-1",
369
+ input: options.input,
370
+ voice: options.voice || "alloy"
371
+ })
372
+ }, false);
373
+ if (!res.ok) {
374
+ const err = await res.json().catch(() => ({ error: res.statusText }));
375
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
376
+ }
377
+ this._requestCount++;
378
+ return res.arrayBuffer();
379
+ }
380
+ /** Legacy completions endpoint */
381
+ async completions(options) {
382
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/completions`, {
383
+ method: "POST",
384
+ headers: this.headers,
385
+ body: JSON.stringify({
386
+ model: options.model || this.model,
387
+ prompt: options.prompt,
388
+ temperature: options.temperature,
389
+ max_tokens: options.maxTokens,
390
+ stop: options.stop,
391
+ top_p: options.topP
392
+ })
393
+ }, false);
394
+ if (!res.ok) {
395
+ const err = await res.json().catch(() => ({ error: res.statusText }));
396
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
397
+ }
398
+ this._requestCount++;
399
+ return res.json();
400
+ }
401
+ /** Audio transcription (speech-to-text) */
402
+ async transcribe(file, options) {
403
+ const formData = new FormData();
404
+ formData.append("file", file, "audio.webm");
405
+ formData.append("model", options?.model || "whisper-1");
406
+ if (options?.language) formData.append("language", options.language);
407
+ if (options?.prompt) formData.append("prompt", options.prompt);
408
+ const headers = { ...this.headers };
409
+ delete headers["Content-Type"];
410
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/transcriptions`, {
411
+ method: "POST",
412
+ headers,
413
+ body: formData
414
+ }, false);
415
+ if (!res.ok) {
416
+ const err = await res.json().catch(() => ({ error: res.statusText }));
417
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
418
+ }
419
+ this._requestCount++;
420
+ return res.json();
421
+ }
422
+ /** Create a fine-tuning job */
423
+ async fineTuneCreate(options) {
424
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/fine_tuning/jobs`, {
425
+ method: "POST",
426
+ headers: this.headers,
427
+ body: JSON.stringify(options)
428
+ }, false);
429
+ if (!res.ok) {
430
+ const err = await res.json().catch(() => ({ error: res.statusText }));
431
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
432
+ }
433
+ this._requestCount++;
434
+ return res.json();
435
+ }
436
+ /** List fine-tuning jobs */
437
+ async fineTuneList() {
438
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/fine_tuning/jobs`, {
439
+ headers: this.headers
440
+ }, false);
441
+ if (!res.ok) throw new TCloudError(res.status, "Failed to fetch fine-tuning jobs");
442
+ return res.json();
443
+ }
444
+ /** Submit a batch of chat requests */
445
+ async batch(requests) {
446
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/batch`, {
447
+ method: "POST",
448
+ headers: this.headers,
449
+ body: JSON.stringify({ requests })
450
+ }, false);
451
+ if (!res.ok) {
452
+ const err = await res.json().catch(() => ({ error: res.statusText }));
453
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
454
+ }
455
+ return res.json();
456
+ }
457
+ /** Get batch job status */
458
+ async batchStatus(jobId) {
459
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/batch?id=${jobId}`, {
460
+ headers: this.headers
461
+ }, false);
462
+ if (!res.ok) throw new TCloudError(res.status, "Failed to fetch batch status");
463
+ return res.json();
464
+ }
465
+ /** Generate video */
466
+ async videoGenerate(options) {
467
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/video/generate`, {
468
+ method: "POST",
469
+ headers: this.headers,
470
+ body: JSON.stringify(options)
471
+ }, false);
472
+ if (!res.ok) {
473
+ const err = await res.json().catch(() => ({ error: res.statusText }));
474
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
475
+ }
476
+ this._requestCount++;
477
+ return res.json();
478
+ }
479
+ /** Get video generation status */
480
+ async videoStatus(id) {
481
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/video?id=${id}`, {
482
+ headers: this.headers
483
+ }, false);
484
+ if (!res.ok) throw new TCloudError(res.status, "Failed to fetch video status");
485
+ return res.json();
486
+ }
289
487
  /** Search models by name, provider, or capability */
290
488
  async searchModels(query) {
291
489
  const all = await this.models();
@@ -2,7 +2,7 @@ import {
2
2
  TCloudClient,
3
3
  createShieldedClient,
4
4
  generateWallet
5
- } from "./chunk-FL352XGA.js";
5
+ } from "./chunk-KVXWEAK3.js";
6
6
 
7
7
  // src/index.ts
8
8
  var TCloud = class _TCloud extends TCloudClient {
package/dist/cli.cjs CHANGED
@@ -84,14 +84,23 @@ var TCloudClient = class {
84
84
  this.limits = config.limits;
85
85
  this.headers = {
86
86
  "Content-Type": "application/json",
87
- "X-Tangle-Client": "tcloud-sdk/0.1.0"
87
+ "X-Tangle-Client": "tcloud-sdk/0.1.4"
88
88
  };
89
89
  if (this.apiKey) {
90
90
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
91
91
  }
92
+ if (config.routing?.mode) {
93
+ this.headers["X-Tangle-Routing"] = config.routing.mode;
94
+ }
92
95
  if (config.routing?.prefer) {
93
96
  this.headers["X-Tangle-Operator"] = config.routing.prefer;
94
97
  }
98
+ if (config.routing?.blueprintId) {
99
+ this.headers["X-Tangle-Blueprint"] = config.routing.blueprintId;
100
+ }
101
+ if (config.routing?.serviceId) {
102
+ this.headers["X-Tangle-Service"] = config.routing.serviceId;
103
+ }
95
104
  if (config.routing?.region) {
96
105
  this.headers["X-Tangle-Region"] = config.routing.region;
97
106
  }
@@ -128,12 +137,19 @@ var TCloudClient = class {
128
137
  if (pct >= 0.8) this.limits.onLimitWarning({ type: "total", current: this._totalSpent, limit: this.limits.maxTotalSpend });
129
138
  }
130
139
  }
131
- /** Track cost after a response */
132
- trackCost(completion) {
140
+ /** Track cost after a response, using actual pricing from response headers when available */
141
+ trackCost(completion, res) {
133
142
  this._requestCount++;
134
143
  if (completion.usage) {
135
- const tokens = completion.usage.total_tokens || 0;
136
- const estimatedCost = tokens * 1e-6;
144
+ let estimatedCost;
145
+ const inputPrice = res ? parseFloat(res.headers.get("x-tangle-price-input") || "0") : 0;
146
+ const outputPrice = res ? parseFloat(res.headers.get("x-tangle-price-output") || "0") : 0;
147
+ if (inputPrice > 0 || outputPrice > 0) {
148
+ estimatedCost = (completion.usage.prompt_tokens || 0) * inputPrice + (completion.usage.completion_tokens || 0) * outputPrice;
149
+ } else {
150
+ const tokens = completion.usage.total_tokens || 0;
151
+ estimatedCost = tokens * 1e-6;
152
+ }
137
153
  this._totalSpent += estimatedCost;
138
154
  if (this.limits?.maxCostPerRequest && estimatedCost > this.limits.maxCostPerRequest) {
139
155
  this.limits.onLimitReached?.({ type: "cost", current: estimatedCost, limit: this.limits.maxCostPerRequest });
@@ -171,7 +187,7 @@ var TCloudClient = class {
171
187
  throw new TCloudError(res.status, err.error?.message || err.error || err.message || res.statusText);
172
188
  }
173
189
  const completion = await res.json();
174
- this.trackCost(completion);
190
+ this.trackCost(completion, res);
175
191
  return completion;
176
192
  }
177
193
  /** Chat completion (streaming) — returns an async iterator of chunks */
@@ -310,6 +326,188 @@ var TCloudClient = class {
310
326
  }, false);
311
327
  if (!res.ok) throw new TCloudError(res.status, "Failed to revoke key");
312
328
  }
329
+ /** Generate embeddings */
330
+ async embeddings(options) {
331
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/embeddings`, {
332
+ method: "POST",
333
+ headers: this.headers,
334
+ body: JSON.stringify({
335
+ model: options.model || "text-embedding-3-small",
336
+ input: options.input
337
+ })
338
+ }, false);
339
+ if (!res.ok) {
340
+ const err = await res.json().catch(() => ({ error: res.statusText }));
341
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
342
+ }
343
+ this._requestCount++;
344
+ return res.json();
345
+ }
346
+ /** Generate images */
347
+ async imageGenerate(options) {
348
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/images/generations`, {
349
+ method: "POST",
350
+ headers: this.headers,
351
+ body: JSON.stringify({
352
+ model: options.model || "dall-e-3",
353
+ prompt: options.prompt,
354
+ n: options.n,
355
+ size: options.size,
356
+ quality: options.quality,
357
+ response_format: options.response_format
358
+ })
359
+ }, false);
360
+ if (!res.ok) {
361
+ const err = await res.json().catch(() => ({ error: res.statusText }));
362
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
363
+ }
364
+ this._requestCount++;
365
+ return res.json();
366
+ }
367
+ /** Rerank documents by relevance to a query */
368
+ async rerank(options) {
369
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/rerank`, {
370
+ method: "POST",
371
+ headers: this.headers,
372
+ body: JSON.stringify({
373
+ model: options.model || "rerank-english-v3.0",
374
+ query: options.query,
375
+ documents: options.documents,
376
+ top_n: options.top_n
377
+ })
378
+ }, false);
379
+ if (!res.ok) {
380
+ const err = await res.json().catch(() => ({ error: res.statusText }));
381
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
382
+ }
383
+ this._requestCount++;
384
+ return res.json();
385
+ }
386
+ /** Text-to-speech */
387
+ async speech(options) {
388
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/speech`, {
389
+ method: "POST",
390
+ headers: this.headers,
391
+ body: JSON.stringify({
392
+ model: options.model || "tts-1",
393
+ input: options.input,
394
+ voice: options.voice || "alloy"
395
+ })
396
+ }, false);
397
+ if (!res.ok) {
398
+ const err = await res.json().catch(() => ({ error: res.statusText }));
399
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
400
+ }
401
+ this._requestCount++;
402
+ return res.arrayBuffer();
403
+ }
404
+ /** Legacy completions endpoint */
405
+ async completions(options) {
406
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/completions`, {
407
+ method: "POST",
408
+ headers: this.headers,
409
+ body: JSON.stringify({
410
+ model: options.model || this.model,
411
+ prompt: options.prompt,
412
+ temperature: options.temperature,
413
+ max_tokens: options.maxTokens,
414
+ stop: options.stop,
415
+ top_p: options.topP
416
+ })
417
+ }, false);
418
+ if (!res.ok) {
419
+ const err = await res.json().catch(() => ({ error: res.statusText }));
420
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
421
+ }
422
+ this._requestCount++;
423
+ return res.json();
424
+ }
425
+ /** Audio transcription (speech-to-text) */
426
+ async transcribe(file, options) {
427
+ const formData = new FormData();
428
+ formData.append("file", file, "audio.webm");
429
+ formData.append("model", options?.model || "whisper-1");
430
+ if (options?.language) formData.append("language", options.language);
431
+ if (options?.prompt) formData.append("prompt", options.prompt);
432
+ const headers = { ...this.headers };
433
+ delete headers["Content-Type"];
434
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/transcriptions`, {
435
+ method: "POST",
436
+ headers,
437
+ body: formData
438
+ }, false);
439
+ if (!res.ok) {
440
+ const err = await res.json().catch(() => ({ error: res.statusText }));
441
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
442
+ }
443
+ this._requestCount++;
444
+ return res.json();
445
+ }
446
+ /** Create a fine-tuning job */
447
+ async fineTuneCreate(options) {
448
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/fine_tuning/jobs`, {
449
+ method: "POST",
450
+ headers: this.headers,
451
+ body: JSON.stringify(options)
452
+ }, false);
453
+ if (!res.ok) {
454
+ const err = await res.json().catch(() => ({ error: res.statusText }));
455
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
456
+ }
457
+ this._requestCount++;
458
+ return res.json();
459
+ }
460
+ /** List fine-tuning jobs */
461
+ async fineTuneList() {
462
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/fine_tuning/jobs`, {
463
+ headers: this.headers
464
+ }, false);
465
+ if (!res.ok) throw new TCloudError(res.status, "Failed to fetch fine-tuning jobs");
466
+ return res.json();
467
+ }
468
+ /** Submit a batch of chat requests */
469
+ async batch(requests) {
470
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/batch`, {
471
+ method: "POST",
472
+ headers: this.headers,
473
+ body: JSON.stringify({ requests })
474
+ }, false);
475
+ if (!res.ok) {
476
+ const err = await res.json().catch(() => ({ error: res.statusText }));
477
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
478
+ }
479
+ return res.json();
480
+ }
481
+ /** Get batch job status */
482
+ async batchStatus(jobId) {
483
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/batch?id=${jobId}`, {
484
+ headers: this.headers
485
+ }, false);
486
+ if (!res.ok) throw new TCloudError(res.status, "Failed to fetch batch status");
487
+ return res.json();
488
+ }
489
+ /** Generate video */
490
+ async videoGenerate(options) {
491
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/video/generate`, {
492
+ method: "POST",
493
+ headers: this.headers,
494
+ body: JSON.stringify(options)
495
+ }, false);
496
+ if (!res.ok) {
497
+ const err = await res.json().catch(() => ({ error: res.statusText }));
498
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
499
+ }
500
+ this._requestCount++;
501
+ return res.json();
502
+ }
503
+ /** Get video generation status */
504
+ async videoStatus(id) {
505
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/video?id=${id}`, {
506
+ headers: this.headers
507
+ }, false);
508
+ if (!res.ok) throw new TCloudError(res.status, "Failed to fetch video status");
509
+ return res.json();
510
+ }
313
511
  /** Search models by name, provider, or capability */
314
512
  async searchModels(query) {
315
513
  const all = await this.models();
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TCloud
4
- } from "./chunk-76AB7HOV.js";
4
+ } from "./chunk-PILYAKCF.js";
5
5
  import {
6
6
  generateWallet
7
- } from "./chunk-FL352XGA.js";
7
+ } from "./chunk-KVXWEAK3.js";
8
8
 
9
9
  // src/cli.ts
10
10
  import { Command } from "commander";