@tangle-network/tcloud 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # tcloud
2
2
 
3
- TypeScript SDK and CLI for [Tangle AI Cloud](https://tangleai.cloud) — decentralized LLM inference with operator routing, reputation-based selection, and anonymous payments via ShieldedCredits.
3
+ TypeScript SDK and CLI for [Tangle AI Cloud](https://router.tangle.tools) — decentralized LLM inference with operator routing, reputation-based selection, and anonymous payments via ShieldedCredits.
4
4
 
5
5
  Zero framework dependencies. Pure `fetch` + SSE. Works in Node.js, Deno, Bun, and edge runtimes.
6
6
 
@@ -281,7 +281,7 @@ Wallets use BIP-39 mnemonics with BIP-44 derivation. Private keys are encrypted
281
281
  Config stored in `~/.tcloud/config.json`:
282
282
 
283
283
  ```bash
284
- tcloud config --api-url https://api.tangleai.cloud
284
+ tcloud config --api-url https://router.tangle.tools
285
285
  tcloud config --model gpt-4o-mini
286
286
  ```
287
287
 
@@ -299,7 +299,7 @@ import OpenAI from 'openai'
299
299
 
300
300
  const client = new OpenAI({
301
301
  apiKey: 'sk-tan-...',
302
- baseURL: 'https://api.tangleai.cloud/v1',
302
+ baseURL: 'https://router.tangle.tools/v1',
303
303
  })
304
304
 
305
305
  const completion = await client.chat.completions.create({
@@ -318,7 +318,7 @@ import { generateText } from 'ai'
318
318
 
319
319
  const tangle = createOpenAI({
320
320
  apiKey: 'sk-tan-...',
321
- baseURL: 'https://api.tangleai.cloud/v1',
321
+ baseURL: 'https://router.tangle.tools/v1',
322
322
  })
323
323
 
324
324
  const { text } = await generateText({
@@ -2,7 +2,7 @@ import {
2
2
  TCloudClient,
3
3
  createShieldedClient,
4
4
  generateWallet
5
- } from "./chunk-4AOQNUQ3.js";
5
+ } from "./chunk-YKLHAS4E.js";
6
6
 
7
7
  // src/index.ts
8
8
  var TCloud = class _TCloud extends TCloudClient {
@@ -3,7 +3,7 @@ import { privateKeyToAccount } from "viem/accounts";
3
3
  import { keccak256, encodeAbiParameters, parseAbiParameters, concat, toBytes } from "viem";
4
4
 
5
5
  // src/client.ts
6
- var DEFAULT_BASE_URL = "https://api.tangleai.cloud/v1";
6
+ var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
7
7
  async function proxiedFetch(privacy, url, init, streaming) {
8
8
  if (!privacy || privacy.mode === "direct") {
9
9
  return fetch(url, init);
@@ -60,7 +60,7 @@ 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.3"
64
64
  };
65
65
  if (this.apiKey) {
66
66
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -68,6 +68,12 @@ var TCloudClient = class {
68
68
  if (config.routing?.prefer) {
69
69
  this.headers["X-Tangle-Operator"] = config.routing.prefer;
70
70
  }
71
+ if (config.routing?.blueprintId) {
72
+ this.headers["X-Tangle-Blueprint"] = config.routing.blueprintId;
73
+ }
74
+ if (config.routing?.serviceId) {
75
+ this.headers["X-Tangle-Service"] = config.routing.serviceId;
76
+ }
71
77
  if (config.routing?.region) {
72
78
  this.headers["X-Tangle-Region"] = config.routing.region;
73
79
  }
@@ -104,12 +110,19 @@ var TCloudClient = class {
104
110
  if (pct >= 0.8) this.limits.onLimitWarning({ type: "total", current: this._totalSpent, limit: this.limits.maxTotalSpend });
105
111
  }
106
112
  }
107
- /** Track cost after a response */
108
- trackCost(completion) {
113
+ /** Track cost after a response, using actual pricing from response headers when available */
114
+ trackCost(completion, res) {
109
115
  this._requestCount++;
110
116
  if (completion.usage) {
111
- const tokens = completion.usage.total_tokens || 0;
112
- const estimatedCost = tokens * 1e-6;
117
+ let estimatedCost;
118
+ const inputPrice = res ? parseFloat(res.headers.get("x-tangle-price-input") || "0") : 0;
119
+ const outputPrice = res ? parseFloat(res.headers.get("x-tangle-price-output") || "0") : 0;
120
+ if (inputPrice > 0 || outputPrice > 0) {
121
+ estimatedCost = (completion.usage.prompt_tokens || 0) * inputPrice + (completion.usage.completion_tokens || 0) * outputPrice;
122
+ } else {
123
+ const tokens = completion.usage.total_tokens || 0;
124
+ estimatedCost = tokens * 1e-6;
125
+ }
113
126
  this._totalSpent += estimatedCost;
114
127
  if (this.limits?.maxCostPerRequest && estimatedCost > this.limits.maxCostPerRequest) {
115
128
  this.limits.onLimitReached?.({ type: "cost", current: estimatedCost, limit: this.limits.maxCostPerRequest });
@@ -147,7 +160,7 @@ var TCloudClient = class {
147
160
  throw new TCloudError(res.status, err.error?.message || err.error || err.message || res.statusText);
148
161
  }
149
162
  const completion = await res.json();
150
- this.trackCost(completion);
163
+ this.trackCost(completion, res);
151
164
  return completion;
152
165
  }
153
166
  /** Chat completion (streaming) — returns an async iterator of chunks */
@@ -286,6 +299,81 @@ var TCloudClient = class {
286
299
  }, false);
287
300
  if (!res.ok) throw new TCloudError(res.status, "Failed to revoke key");
288
301
  }
302
+ /** Generate embeddings */
303
+ async embeddings(options) {
304
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/embeddings`, {
305
+ method: "POST",
306
+ headers: this.headers,
307
+ body: JSON.stringify({
308
+ model: options.model || "text-embedding-3-small",
309
+ input: options.input
310
+ })
311
+ }, false);
312
+ if (!res.ok) {
313
+ const err = await res.json().catch(() => ({ error: res.statusText }));
314
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
315
+ }
316
+ this._requestCount++;
317
+ return res.json();
318
+ }
319
+ /** Generate images */
320
+ async imageGenerate(options) {
321
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/images/generations`, {
322
+ method: "POST",
323
+ headers: this.headers,
324
+ body: JSON.stringify({
325
+ model: options.model || "dall-e-3",
326
+ prompt: options.prompt,
327
+ n: options.n,
328
+ size: options.size,
329
+ quality: options.quality,
330
+ response_format: options.response_format
331
+ })
332
+ }, false);
333
+ if (!res.ok) {
334
+ const err = await res.json().catch(() => ({ error: res.statusText }));
335
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
336
+ }
337
+ this._requestCount++;
338
+ return res.json();
339
+ }
340
+ /** Rerank documents by relevance to a query */
341
+ async rerank(options) {
342
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/rerank`, {
343
+ method: "POST",
344
+ headers: this.headers,
345
+ body: JSON.stringify({
346
+ model: options.model || "rerank-english-v3.0",
347
+ query: options.query,
348
+ documents: options.documents,
349
+ top_n: options.top_n
350
+ })
351
+ }, false);
352
+ if (!res.ok) {
353
+ const err = await res.json().catch(() => ({ error: res.statusText }));
354
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
355
+ }
356
+ this._requestCount++;
357
+ return res.json();
358
+ }
359
+ /** Text-to-speech */
360
+ async speech(options) {
361
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/speech`, {
362
+ method: "POST",
363
+ headers: this.headers,
364
+ body: JSON.stringify({
365
+ model: options.model || "tts-1",
366
+ input: options.input,
367
+ voice: options.voice || "alloy"
368
+ })
369
+ }, false);
370
+ if (!res.ok) {
371
+ const err = await res.json().catch(() => ({ error: res.statusText }));
372
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
373
+ }
374
+ this._requestCount++;
375
+ return res.arrayBuffer();
376
+ }
289
377
  /** Search models by name, provider, or capability */
290
378
  async searchModels(query) {
291
379
  const all = await this.models();
package/dist/cli.cjs CHANGED
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  var import_commander = require("commander");
28
28
 
29
29
  // src/client.ts
30
- var DEFAULT_BASE_URL = "https://api.tangleai.cloud/v1";
30
+ var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
31
31
  async function proxiedFetch(privacy, url, init, streaming) {
32
32
  if (!privacy || privacy.mode === "direct") {
33
33
  return fetch(url, init);
@@ -84,7 +84,7 @@ 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.3"
88
88
  };
89
89
  if (this.apiKey) {
90
90
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -92,6 +92,12 @@ var TCloudClient = class {
92
92
  if (config.routing?.prefer) {
93
93
  this.headers["X-Tangle-Operator"] = config.routing.prefer;
94
94
  }
95
+ if (config.routing?.blueprintId) {
96
+ this.headers["X-Tangle-Blueprint"] = config.routing.blueprintId;
97
+ }
98
+ if (config.routing?.serviceId) {
99
+ this.headers["X-Tangle-Service"] = config.routing.serviceId;
100
+ }
95
101
  if (config.routing?.region) {
96
102
  this.headers["X-Tangle-Region"] = config.routing.region;
97
103
  }
@@ -128,12 +134,19 @@ var TCloudClient = class {
128
134
  if (pct >= 0.8) this.limits.onLimitWarning({ type: "total", current: this._totalSpent, limit: this.limits.maxTotalSpend });
129
135
  }
130
136
  }
131
- /** Track cost after a response */
132
- trackCost(completion) {
137
+ /** Track cost after a response, using actual pricing from response headers when available */
138
+ trackCost(completion, res) {
133
139
  this._requestCount++;
134
140
  if (completion.usage) {
135
- const tokens = completion.usage.total_tokens || 0;
136
- const estimatedCost = tokens * 1e-6;
141
+ let estimatedCost;
142
+ const inputPrice = res ? parseFloat(res.headers.get("x-tangle-price-input") || "0") : 0;
143
+ const outputPrice = res ? parseFloat(res.headers.get("x-tangle-price-output") || "0") : 0;
144
+ if (inputPrice > 0 || outputPrice > 0) {
145
+ estimatedCost = (completion.usage.prompt_tokens || 0) * inputPrice + (completion.usage.completion_tokens || 0) * outputPrice;
146
+ } else {
147
+ const tokens = completion.usage.total_tokens || 0;
148
+ estimatedCost = tokens * 1e-6;
149
+ }
137
150
  this._totalSpent += estimatedCost;
138
151
  if (this.limits?.maxCostPerRequest && estimatedCost > this.limits.maxCostPerRequest) {
139
152
  this.limits.onLimitReached?.({ type: "cost", current: estimatedCost, limit: this.limits.maxCostPerRequest });
@@ -171,7 +184,7 @@ var TCloudClient = class {
171
184
  throw new TCloudError(res.status, err.error?.message || err.error || err.message || res.statusText);
172
185
  }
173
186
  const completion = await res.json();
174
- this.trackCost(completion);
187
+ this.trackCost(completion, res);
175
188
  return completion;
176
189
  }
177
190
  /** Chat completion (streaming) — returns an async iterator of chunks */
@@ -310,6 +323,81 @@ var TCloudClient = class {
310
323
  }, false);
311
324
  if (!res.ok) throw new TCloudError(res.status, "Failed to revoke key");
312
325
  }
326
+ /** Generate embeddings */
327
+ async embeddings(options) {
328
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/embeddings`, {
329
+ method: "POST",
330
+ headers: this.headers,
331
+ body: JSON.stringify({
332
+ model: options.model || "text-embedding-3-small",
333
+ input: options.input
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
+ /** Generate images */
344
+ async imageGenerate(options) {
345
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/images/generations`, {
346
+ method: "POST",
347
+ headers: this.headers,
348
+ body: JSON.stringify({
349
+ model: options.model || "dall-e-3",
350
+ prompt: options.prompt,
351
+ n: options.n,
352
+ size: options.size,
353
+ quality: options.quality,
354
+ response_format: options.response_format
355
+ })
356
+ }, false);
357
+ if (!res.ok) {
358
+ const err = await res.json().catch(() => ({ error: res.statusText }));
359
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
360
+ }
361
+ this._requestCount++;
362
+ return res.json();
363
+ }
364
+ /** Rerank documents by relevance to a query */
365
+ async rerank(options) {
366
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/rerank`, {
367
+ method: "POST",
368
+ headers: this.headers,
369
+ body: JSON.stringify({
370
+ model: options.model || "rerank-english-v3.0",
371
+ query: options.query,
372
+ documents: options.documents,
373
+ top_n: options.top_n
374
+ })
375
+ }, false);
376
+ if (!res.ok) {
377
+ const err = await res.json().catch(() => ({ error: res.statusText }));
378
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
379
+ }
380
+ this._requestCount++;
381
+ return res.json();
382
+ }
383
+ /** Text-to-speech */
384
+ async speech(options) {
385
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/speech`, {
386
+ method: "POST",
387
+ headers: this.headers,
388
+ body: JSON.stringify({
389
+ model: options.model || "tts-1",
390
+ input: options.input,
391
+ voice: options.voice || "alloy"
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.arrayBuffer();
400
+ }
313
401
  /** Search models by name, provider, or capability */
314
402
  async searchModels(query) {
315
403
  const all = await this.models();
@@ -642,7 +730,7 @@ function ensureDir() {
642
730
  function loadConfig() {
643
731
  ensureDir();
644
732
  if (fs.existsSync(CONFIG_FILE)) return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
645
- return { apiUrl: "https://api.tangleai.cloud", defaultModel: "gpt-4o-mini", chainId: 3799 };
733
+ return { apiUrl: "https://router.tangle.tools", defaultModel: "gpt-4o-mini", chainId: 3799 };
646
734
  }
647
735
  function saveConfig(c) {
648
736
  ensureDir();
@@ -859,7 +947,7 @@ credits.command("add").description("Add credits").argument("<amount>").action(as
859
947
  });
860
948
  credits.command("fund").description("Fund shielded credits from pool").action(() => {
861
949
  console.log("Shielded credit funding requires integration with the VAnchor pool.");
862
- console.log("See: https://docs.tangleai.cloud/privacy/funding");
950
+ console.log("See: https://docs.tangle.tools/privacy/funding");
863
951
  });
864
952
  var keys = program.command("keys").description("API key management");
865
953
  keys.command("create").description("Create API key").argument("<name>").action(async (name) => {
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TCloud
4
- } from "./chunk-YORNEPCU.js";
4
+ } from "./chunk-G5LUZZKT.js";
5
5
  import {
6
6
  generateWallet
7
- } from "./chunk-4AOQNUQ3.js";
7
+ } from "./chunk-YKLHAS4E.js";
8
8
 
9
9
  // src/cli.ts
10
10
  import { Command } from "commander";
@@ -20,7 +20,7 @@ function ensureDir() {
20
20
  function loadConfig() {
21
21
  ensureDir();
22
22
  if (fs.existsSync(CONFIG_FILE)) return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
23
- return { apiUrl: "https://api.tangleai.cloud", defaultModel: "gpt-4o-mini", chainId: 3799 };
23
+ return { apiUrl: "https://router.tangle.tools", defaultModel: "gpt-4o-mini", chainId: 3799 };
24
24
  }
25
25
  function saveConfig(c) {
26
26
  ensureDir();
@@ -237,7 +237,7 @@ credits.command("add").description("Add credits").argument("<amount>").action(as
237
237
  });
238
238
  credits.command("fund").description("Fund shielded credits from pool").action(() => {
239
239
  console.log("Shielded credit funding requires integration with the VAnchor pool.");
240
- console.log("See: https://docs.tangleai.cloud/privacy/funding");
240
+ console.log("See: https://docs.tangle.tools/privacy/funding");
241
241
  });
242
242
  var keys = program.command("keys").description("API key management");
243
243
  keys.command("create").description("Create API key").argument("<name>").action(async (name) => {
package/dist/index.cjs CHANGED
@@ -41,7 +41,7 @@ __export(index_exports, {
41
41
  module.exports = __toCommonJS(index_exports);
42
42
 
43
43
  // src/client.ts
44
- var DEFAULT_BASE_URL = "https://api.tangleai.cloud/v1";
44
+ var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
45
45
  async function proxiedFetch(privacy, url, init, streaming) {
46
46
  if (!privacy || privacy.mode === "direct") {
47
47
  return fetch(url, init);
@@ -98,7 +98,7 @@ var TCloudClient = class {
98
98
  this.limits = config.limits;
99
99
  this.headers = {
100
100
  "Content-Type": "application/json",
101
- "X-Tangle-Client": "tcloud-sdk/0.1.0"
101
+ "X-Tangle-Client": "tcloud-sdk/0.1.3"
102
102
  };
103
103
  if (this.apiKey) {
104
104
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -106,6 +106,12 @@ var TCloudClient = class {
106
106
  if (config.routing?.prefer) {
107
107
  this.headers["X-Tangle-Operator"] = config.routing.prefer;
108
108
  }
109
+ if (config.routing?.blueprintId) {
110
+ this.headers["X-Tangle-Blueprint"] = config.routing.blueprintId;
111
+ }
112
+ if (config.routing?.serviceId) {
113
+ this.headers["X-Tangle-Service"] = config.routing.serviceId;
114
+ }
109
115
  if (config.routing?.region) {
110
116
  this.headers["X-Tangle-Region"] = config.routing.region;
111
117
  }
@@ -142,12 +148,19 @@ var TCloudClient = class {
142
148
  if (pct >= 0.8) this.limits.onLimitWarning({ type: "total", current: this._totalSpent, limit: this.limits.maxTotalSpend });
143
149
  }
144
150
  }
145
- /** Track cost after a response */
146
- trackCost(completion) {
151
+ /** Track cost after a response, using actual pricing from response headers when available */
152
+ trackCost(completion, res) {
147
153
  this._requestCount++;
148
154
  if (completion.usage) {
149
- const tokens = completion.usage.total_tokens || 0;
150
- const estimatedCost = tokens * 1e-6;
155
+ let estimatedCost;
156
+ const inputPrice = res ? parseFloat(res.headers.get("x-tangle-price-input") || "0") : 0;
157
+ const outputPrice = res ? parseFloat(res.headers.get("x-tangle-price-output") || "0") : 0;
158
+ if (inputPrice > 0 || outputPrice > 0) {
159
+ estimatedCost = (completion.usage.prompt_tokens || 0) * inputPrice + (completion.usage.completion_tokens || 0) * outputPrice;
160
+ } else {
161
+ const tokens = completion.usage.total_tokens || 0;
162
+ estimatedCost = tokens * 1e-6;
163
+ }
151
164
  this._totalSpent += estimatedCost;
152
165
  if (this.limits?.maxCostPerRequest && estimatedCost > this.limits.maxCostPerRequest) {
153
166
  this.limits.onLimitReached?.({ type: "cost", current: estimatedCost, limit: this.limits.maxCostPerRequest });
@@ -185,7 +198,7 @@ var TCloudClient = class {
185
198
  throw new TCloudError(res.status, err.error?.message || err.error || err.message || res.statusText);
186
199
  }
187
200
  const completion = await res.json();
188
- this.trackCost(completion);
201
+ this.trackCost(completion, res);
189
202
  return completion;
190
203
  }
191
204
  /** Chat completion (streaming) — returns an async iterator of chunks */
@@ -324,6 +337,81 @@ var TCloudClient = class {
324
337
  }, false);
325
338
  if (!res.ok) throw new TCloudError(res.status, "Failed to revoke key");
326
339
  }
340
+ /** Generate embeddings */
341
+ async embeddings(options) {
342
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/embeddings`, {
343
+ method: "POST",
344
+ headers: this.headers,
345
+ body: JSON.stringify({
346
+ model: options.model || "text-embedding-3-small",
347
+ input: options.input
348
+ })
349
+ }, false);
350
+ if (!res.ok) {
351
+ const err = await res.json().catch(() => ({ error: res.statusText }));
352
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
353
+ }
354
+ this._requestCount++;
355
+ return res.json();
356
+ }
357
+ /** Generate images */
358
+ async imageGenerate(options) {
359
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/images/generations`, {
360
+ method: "POST",
361
+ headers: this.headers,
362
+ body: JSON.stringify({
363
+ model: options.model || "dall-e-3",
364
+ prompt: options.prompt,
365
+ n: options.n,
366
+ size: options.size,
367
+ quality: options.quality,
368
+ response_format: options.response_format
369
+ })
370
+ }, false);
371
+ if (!res.ok) {
372
+ const err = await res.json().catch(() => ({ error: res.statusText }));
373
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
374
+ }
375
+ this._requestCount++;
376
+ return res.json();
377
+ }
378
+ /** Rerank documents by relevance to a query */
379
+ async rerank(options) {
380
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/rerank`, {
381
+ method: "POST",
382
+ headers: this.headers,
383
+ body: JSON.stringify({
384
+ model: options.model || "rerank-english-v3.0",
385
+ query: options.query,
386
+ documents: options.documents,
387
+ top_n: options.top_n
388
+ })
389
+ }, false);
390
+ if (!res.ok) {
391
+ const err = await res.json().catch(() => ({ error: res.statusText }));
392
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
393
+ }
394
+ this._requestCount++;
395
+ return res.json();
396
+ }
397
+ /** Text-to-speech */
398
+ async speech(options) {
399
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/speech`, {
400
+ method: "POST",
401
+ headers: this.headers,
402
+ body: JSON.stringify({
403
+ model: options.model || "tts-1",
404
+ input: options.input,
405
+ voice: options.voice || "alloy"
406
+ })
407
+ }, false);
408
+ if (!res.ok) {
409
+ const err = await res.json().catch(() => ({ error: res.statusText }));
410
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
411
+ }
412
+ this._requestCount++;
413
+ return res.arrayBuffer();
414
+ }
327
415
  /** Search models by name, provider, or capability */
328
416
  async searchModels(query) {
329
417
  const all = await this.models();
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TCloudClient, a as TCloudConfig, S as ShieldedWallet, g as generateWallet } from './shielded-BRhsV-s-.cjs';
2
- export { C as ChatCompletion, b as ChatCompletionChunk, c as ChatMessage, d as ChatOptions, e as CreditBalance, M as Model, O as Operator, P as PrivacyConfig, R as RoutingConfig, f as ShieldedConfig, h as SpendAuth, i as SpendingLimits, j as TCloudError, k as createShieldedClient, l as estimateCost, s as signSpendAuth } from './shielded-BRhsV-s-.cjs';
1
+ import { T as TCloudClient, a as TCloudConfig, S as ShieldedWallet, g as generateWallet } from './shielded-xDNVqK4a.cjs';
2
+ export { C as ChatCompletion, b as ChatCompletionChunk, c as ChatMessage, d as ChatOptions, e as CreditBalance, E as EmbeddingOptions, f as EmbeddingResponse, I as ImageGenerateOptions, h as ImageResponse, M as Model, O as Operator, P as PrivacyConfig, R as RerankOptions, i as RerankResponse, j as RoutingConfig, k as ShieldedConfig, l as SpendAuth, m as SpendingLimits, n as TCloudError, o as createShieldedClient, p as estimateCost, s as signSpendAuth } from './shielded-xDNVqK4a.cjs';
3
3
  import 'viem';
4
4
 
5
5
  declare class TCloud extends TCloudClient {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TCloudClient, a as TCloudConfig, S as ShieldedWallet, g as generateWallet } from './shielded-BRhsV-s-.js';
2
- export { C as ChatCompletion, b as ChatCompletionChunk, c as ChatMessage, d as ChatOptions, e as CreditBalance, M as Model, O as Operator, P as PrivacyConfig, R as RoutingConfig, f as ShieldedConfig, h as SpendAuth, i as SpendingLimits, j as TCloudError, k as createShieldedClient, l as estimateCost, s as signSpendAuth } from './shielded-BRhsV-s-.js';
1
+ import { T as TCloudClient, a as TCloudConfig, S as ShieldedWallet, g as generateWallet } from './shielded-xDNVqK4a.js';
2
+ export { C as ChatCompletion, b as ChatCompletionChunk, c as ChatMessage, d as ChatOptions, e as CreditBalance, E as EmbeddingOptions, f as EmbeddingResponse, I as ImageGenerateOptions, h as ImageResponse, M as Model, O as Operator, P as PrivacyConfig, R as RerankOptions, i as RerankResponse, j as RoutingConfig, k as ShieldedConfig, l as SpendAuth, m as SpendingLimits, n as TCloudError, o as createShieldedClient, p as estimateCost, s as signSpendAuth } from './shielded-xDNVqK4a.js';
3
3
  import 'viem';
4
4
 
5
5
  declare class TCloud extends TCloudClient {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TCloud
3
- } from "./chunk-YORNEPCU.js";
3
+ } from "./chunk-G5LUZZKT.js";
4
4
  import {
5
5
  TCloudClient,
6
6
  TCloudError,
@@ -8,7 +8,7 @@ import {
8
8
  estimateCost,
9
9
  generateWallet,
10
10
  signSpendAuth
11
- } from "./chunk-4AOQNUQ3.js";
11
+ } from "./chunk-YKLHAS4E.js";
12
12
  export {
13
13
  TCloud,
14
14
  TCloudClient,
@@ -2,7 +2,7 @@ import { Hex } from 'viem';
2
2
 
3
3
  /** Core types for the tcloud SDK */
4
4
  interface TCloudConfig {
5
- /** API base URL (default: https://api.tangleai.cloud/v1) */
5
+ /** API base URL (default: https://router.tangle.tools/v1) */
6
6
  baseURL?: string;
7
7
  /** API key for standard (non-private) mode */
8
8
  apiKey?: string;
@@ -38,8 +38,12 @@ interface SpendingLimits {
38
38
  }) => void;
39
39
  }
40
40
  interface RoutingConfig {
41
- /** Preferred operator slug */
41
+ /** Preferred operator slug or address */
42
42
  prefer?: string;
43
+ /** Blueprint ID — route to operators under this Blueprint */
44
+ blueprintId?: string;
45
+ /** Service instance ID — route to a specific service instance */
46
+ serviceId?: string;
43
47
  /** Routing strategy */
44
48
  strategy?: 'lowest-latency' | 'lowest-price' | 'highest-reputation' | 'round-robin';
45
49
  /** Region filter */
@@ -47,6 +51,51 @@ interface RoutingConfig {
47
51
  /** Fallback operator slugs (tried in order) */
48
52
  fallback?: string[];
49
53
  }
54
+ interface EmbeddingOptions {
55
+ model?: string;
56
+ input: string | string[];
57
+ }
58
+ interface EmbeddingResponse {
59
+ object: string;
60
+ data: {
61
+ object: string;
62
+ embedding: number[];
63
+ index: number;
64
+ }[];
65
+ model: string;
66
+ usage: {
67
+ prompt_tokens: number;
68
+ total_tokens: number;
69
+ };
70
+ }
71
+ interface ImageGenerateOptions {
72
+ model?: string;
73
+ prompt: string;
74
+ n?: number;
75
+ size?: string;
76
+ quality?: string;
77
+ response_format?: 'url' | 'b64_json';
78
+ }
79
+ interface ImageResponse {
80
+ created: number;
81
+ data: {
82
+ url?: string;
83
+ b64_json?: string;
84
+ revised_prompt?: string;
85
+ }[];
86
+ }
87
+ interface RerankOptions {
88
+ model?: string;
89
+ query: string;
90
+ documents: string[];
91
+ top_n?: number;
92
+ }
93
+ interface RerankResponse {
94
+ results: {
95
+ index: number;
96
+ relevance_score: number;
97
+ }[];
98
+ }
50
99
  interface PrivacyConfig {
51
100
  /** 'direct' — no proxy (default). 'relayer' — route through tcloud-relayer. 'socks5' — route through SOCKS5 proxy (e.g. Tor). */
52
101
  mode: 'direct' | 'relayer' | 'socks5';
@@ -225,7 +274,7 @@ declare class TCloudClient {
225
274
  };
226
275
  /** Check spending limits before a request. Throws TCloudError if blocked. */
227
276
  private checkLimits;
228
- /** Track cost after a response */
277
+ /** Track cost after a response, using actual pricing from response headers when available */
229
278
  private trackCost;
230
279
  /** Chat completion (non-streaming) */
231
280
  chat(options: ChatOptions): Promise<ChatCompletion>;
@@ -265,6 +314,18 @@ declare class TCloudClient {
265
314
  }[]>;
266
315
  /** Revoke an API key */
267
316
  revokeKey(id: string): Promise<void>;
317
+ /** Generate embeddings */
318
+ embeddings(options: EmbeddingOptions): Promise<EmbeddingResponse>;
319
+ /** Generate images */
320
+ imageGenerate(options: ImageGenerateOptions): Promise<ImageResponse>;
321
+ /** Rerank documents by relevance to a query */
322
+ rerank(options: RerankOptions): Promise<RerankResponse>;
323
+ /** Text-to-speech */
324
+ speech(options: {
325
+ model?: string;
326
+ input: string;
327
+ voice?: string;
328
+ }): Promise<ArrayBuffer>;
268
329
  /** Search models by name, provider, or capability */
269
330
  searchModels(query: string): Promise<Model[]>;
270
331
  /** Estimate cost for a request (without sending it) */
@@ -340,4 +401,4 @@ declare function createShieldedClient(config?: TCloudConfig & {
340
401
  stopAutoReplenish: () => void;
341
402
  };
342
403
 
343
- export { type AutoReplenishOptions as A, type ChatCompletion as C, type Model as M, type Operator as O, type PrivacyConfig as P, type RoutingConfig as R, type ShieldedWallet as S, TCloudClient as T, type TCloudConfig as a, type ChatCompletionChunk as b, type ChatMessage as c, type ChatOptions as d, type CreditBalance as e, type ShieldedConfig as f, generateWallet as g, type SpendAuth as h, type SpendingLimits as i, TCloudError as j, createShieldedClient as k, estimateCost as l, signSpendAuth as s };
404
+ export { type AutoReplenishOptions as A, type ChatCompletion as C, type EmbeddingOptions as E, type ImageGenerateOptions as I, type Model as M, type Operator as O, type PrivacyConfig as P, type RerankOptions as R, type ShieldedWallet as S, TCloudClient as T, type TCloudConfig as a, type ChatCompletionChunk as b, type ChatMessage as c, type ChatOptions as d, type CreditBalance as e, type EmbeddingResponse as f, generateWallet as g, type ImageResponse as h, type RerankResponse as i, type RoutingConfig as j, type ShieldedConfig as k, type SpendAuth as l, type SpendingLimits as m, TCloudError as n, createShieldedClient as o, estimateCost as p, signSpendAuth as s };
@@ -2,7 +2,7 @@ import { Hex } from 'viem';
2
2
 
3
3
  /** Core types for the tcloud SDK */
4
4
  interface TCloudConfig {
5
- /** API base URL (default: https://api.tangleai.cloud/v1) */
5
+ /** API base URL (default: https://router.tangle.tools/v1) */
6
6
  baseURL?: string;
7
7
  /** API key for standard (non-private) mode */
8
8
  apiKey?: string;
@@ -38,8 +38,12 @@ interface SpendingLimits {
38
38
  }) => void;
39
39
  }
40
40
  interface RoutingConfig {
41
- /** Preferred operator slug */
41
+ /** Preferred operator slug or address */
42
42
  prefer?: string;
43
+ /** Blueprint ID — route to operators under this Blueprint */
44
+ blueprintId?: string;
45
+ /** Service instance ID — route to a specific service instance */
46
+ serviceId?: string;
43
47
  /** Routing strategy */
44
48
  strategy?: 'lowest-latency' | 'lowest-price' | 'highest-reputation' | 'round-robin';
45
49
  /** Region filter */
@@ -47,6 +51,51 @@ interface RoutingConfig {
47
51
  /** Fallback operator slugs (tried in order) */
48
52
  fallback?: string[];
49
53
  }
54
+ interface EmbeddingOptions {
55
+ model?: string;
56
+ input: string | string[];
57
+ }
58
+ interface EmbeddingResponse {
59
+ object: string;
60
+ data: {
61
+ object: string;
62
+ embedding: number[];
63
+ index: number;
64
+ }[];
65
+ model: string;
66
+ usage: {
67
+ prompt_tokens: number;
68
+ total_tokens: number;
69
+ };
70
+ }
71
+ interface ImageGenerateOptions {
72
+ model?: string;
73
+ prompt: string;
74
+ n?: number;
75
+ size?: string;
76
+ quality?: string;
77
+ response_format?: 'url' | 'b64_json';
78
+ }
79
+ interface ImageResponse {
80
+ created: number;
81
+ data: {
82
+ url?: string;
83
+ b64_json?: string;
84
+ revised_prompt?: string;
85
+ }[];
86
+ }
87
+ interface RerankOptions {
88
+ model?: string;
89
+ query: string;
90
+ documents: string[];
91
+ top_n?: number;
92
+ }
93
+ interface RerankResponse {
94
+ results: {
95
+ index: number;
96
+ relevance_score: number;
97
+ }[];
98
+ }
50
99
  interface PrivacyConfig {
51
100
  /** 'direct' — no proxy (default). 'relayer' — route through tcloud-relayer. 'socks5' — route through SOCKS5 proxy (e.g. Tor). */
52
101
  mode: 'direct' | 'relayer' | 'socks5';
@@ -225,7 +274,7 @@ declare class TCloudClient {
225
274
  };
226
275
  /** Check spending limits before a request. Throws TCloudError if blocked. */
227
276
  private checkLimits;
228
- /** Track cost after a response */
277
+ /** Track cost after a response, using actual pricing from response headers when available */
229
278
  private trackCost;
230
279
  /** Chat completion (non-streaming) */
231
280
  chat(options: ChatOptions): Promise<ChatCompletion>;
@@ -265,6 +314,18 @@ declare class TCloudClient {
265
314
  }[]>;
266
315
  /** Revoke an API key */
267
316
  revokeKey(id: string): Promise<void>;
317
+ /** Generate embeddings */
318
+ embeddings(options: EmbeddingOptions): Promise<EmbeddingResponse>;
319
+ /** Generate images */
320
+ imageGenerate(options: ImageGenerateOptions): Promise<ImageResponse>;
321
+ /** Rerank documents by relevance to a query */
322
+ rerank(options: RerankOptions): Promise<RerankResponse>;
323
+ /** Text-to-speech */
324
+ speech(options: {
325
+ model?: string;
326
+ input: string;
327
+ voice?: string;
328
+ }): Promise<ArrayBuffer>;
268
329
  /** Search models by name, provider, or capability */
269
330
  searchModels(query: string): Promise<Model[]>;
270
331
  /** Estimate cost for a request (without sending it) */
@@ -340,4 +401,4 @@ declare function createShieldedClient(config?: TCloudConfig & {
340
401
  stopAutoReplenish: () => void;
341
402
  };
342
403
 
343
- export { type AutoReplenishOptions as A, type ChatCompletion as C, type Model as M, type Operator as O, type PrivacyConfig as P, type RoutingConfig as R, type ShieldedWallet as S, TCloudClient as T, type TCloudConfig as a, type ChatCompletionChunk as b, type ChatMessage as c, type ChatOptions as d, type CreditBalance as e, type ShieldedConfig as f, generateWallet as g, type SpendAuth as h, type SpendingLimits as i, TCloudError as j, createShieldedClient as k, estimateCost as l, signSpendAuth as s };
404
+ export { type AutoReplenishOptions as A, type ChatCompletion as C, type EmbeddingOptions as E, type ImageGenerateOptions as I, type Model as M, type Operator as O, type PrivacyConfig as P, type RerankOptions as R, type ShieldedWallet as S, TCloudClient as T, type TCloudConfig as a, type ChatCompletionChunk as b, type ChatMessage as c, type ChatOptions as d, type CreditBalance as e, type EmbeddingResponse as f, generateWallet as g, type ImageResponse as h, type RerankResponse as i, type RoutingConfig as j, type ShieldedConfig as k, type SpendAuth as l, type SpendingLimits as m, TCloudError as n, createShieldedClient as o, estimateCost as p, signSpendAuth as s };
package/dist/shielded.cjs CHANGED
@@ -40,7 +40,7 @@ var import_accounts = require("viem/accounts");
40
40
  var import_viem = require("viem");
41
41
 
42
42
  // src/client.ts
43
- var DEFAULT_BASE_URL = "https://api.tangleai.cloud/v1";
43
+ var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
44
44
  async function proxiedFetch(privacy, url, init, streaming) {
45
45
  if (!privacy || privacy.mode === "direct") {
46
46
  return fetch(url, init);
@@ -97,7 +97,7 @@ var TCloudClient = class {
97
97
  this.limits = config.limits;
98
98
  this.headers = {
99
99
  "Content-Type": "application/json",
100
- "X-Tangle-Client": "tcloud-sdk/0.1.0"
100
+ "X-Tangle-Client": "tcloud-sdk/0.1.3"
101
101
  };
102
102
  if (this.apiKey) {
103
103
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -105,6 +105,12 @@ var TCloudClient = class {
105
105
  if (config.routing?.prefer) {
106
106
  this.headers["X-Tangle-Operator"] = config.routing.prefer;
107
107
  }
108
+ if (config.routing?.blueprintId) {
109
+ this.headers["X-Tangle-Blueprint"] = config.routing.blueprintId;
110
+ }
111
+ if (config.routing?.serviceId) {
112
+ this.headers["X-Tangle-Service"] = config.routing.serviceId;
113
+ }
108
114
  if (config.routing?.region) {
109
115
  this.headers["X-Tangle-Region"] = config.routing.region;
110
116
  }
@@ -141,12 +147,19 @@ var TCloudClient = class {
141
147
  if (pct >= 0.8) this.limits.onLimitWarning({ type: "total", current: this._totalSpent, limit: this.limits.maxTotalSpend });
142
148
  }
143
149
  }
144
- /** Track cost after a response */
145
- trackCost(completion) {
150
+ /** Track cost after a response, using actual pricing from response headers when available */
151
+ trackCost(completion, res) {
146
152
  this._requestCount++;
147
153
  if (completion.usage) {
148
- const tokens = completion.usage.total_tokens || 0;
149
- const estimatedCost = tokens * 1e-6;
154
+ let estimatedCost;
155
+ const inputPrice = res ? parseFloat(res.headers.get("x-tangle-price-input") || "0") : 0;
156
+ const outputPrice = res ? parseFloat(res.headers.get("x-tangle-price-output") || "0") : 0;
157
+ if (inputPrice > 0 || outputPrice > 0) {
158
+ estimatedCost = (completion.usage.prompt_tokens || 0) * inputPrice + (completion.usage.completion_tokens || 0) * outputPrice;
159
+ } else {
160
+ const tokens = completion.usage.total_tokens || 0;
161
+ estimatedCost = tokens * 1e-6;
162
+ }
150
163
  this._totalSpent += estimatedCost;
151
164
  if (this.limits?.maxCostPerRequest && estimatedCost > this.limits.maxCostPerRequest) {
152
165
  this.limits.onLimitReached?.({ type: "cost", current: estimatedCost, limit: this.limits.maxCostPerRequest });
@@ -184,7 +197,7 @@ var TCloudClient = class {
184
197
  throw new TCloudError(res.status, err.error?.message || err.error || err.message || res.statusText);
185
198
  }
186
199
  const completion = await res.json();
187
- this.trackCost(completion);
200
+ this.trackCost(completion, res);
188
201
  return completion;
189
202
  }
190
203
  /** Chat completion (streaming) — returns an async iterator of chunks */
@@ -323,6 +336,81 @@ var TCloudClient = class {
323
336
  }, false);
324
337
  if (!res.ok) throw new TCloudError(res.status, "Failed to revoke key");
325
338
  }
339
+ /** Generate embeddings */
340
+ async embeddings(options) {
341
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/embeddings`, {
342
+ method: "POST",
343
+ headers: this.headers,
344
+ body: JSON.stringify({
345
+ model: options.model || "text-embedding-3-small",
346
+ input: options.input
347
+ })
348
+ }, false);
349
+ if (!res.ok) {
350
+ const err = await res.json().catch(() => ({ error: res.statusText }));
351
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
352
+ }
353
+ this._requestCount++;
354
+ return res.json();
355
+ }
356
+ /** Generate images */
357
+ async imageGenerate(options) {
358
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/images/generations`, {
359
+ method: "POST",
360
+ headers: this.headers,
361
+ body: JSON.stringify({
362
+ model: options.model || "dall-e-3",
363
+ prompt: options.prompt,
364
+ n: options.n,
365
+ size: options.size,
366
+ quality: options.quality,
367
+ response_format: options.response_format
368
+ })
369
+ }, false);
370
+ if (!res.ok) {
371
+ const err = await res.json().catch(() => ({ error: res.statusText }));
372
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
373
+ }
374
+ this._requestCount++;
375
+ return res.json();
376
+ }
377
+ /** Rerank documents by relevance to a query */
378
+ async rerank(options) {
379
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/rerank`, {
380
+ method: "POST",
381
+ headers: this.headers,
382
+ body: JSON.stringify({
383
+ model: options.model || "rerank-english-v3.0",
384
+ query: options.query,
385
+ documents: options.documents,
386
+ top_n: options.top_n
387
+ })
388
+ }, false);
389
+ if (!res.ok) {
390
+ const err = await res.json().catch(() => ({ error: res.statusText }));
391
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
392
+ }
393
+ this._requestCount++;
394
+ return res.json();
395
+ }
396
+ /** Text-to-speech */
397
+ async speech(options) {
398
+ const res = await proxiedFetch(this.privacy, `${this.baseURL}/audio/speech`, {
399
+ method: "POST",
400
+ headers: this.headers,
401
+ body: JSON.stringify({
402
+ model: options.model || "tts-1",
403
+ input: options.input,
404
+ voice: options.voice || "alloy"
405
+ })
406
+ }, false);
407
+ if (!res.ok) {
408
+ const err = await res.json().catch(() => ({ error: res.statusText }));
409
+ throw new TCloudError(res.status, err.error?.message || err.error || res.statusText);
410
+ }
411
+ this._requestCount++;
412
+ return res.arrayBuffer();
413
+ }
326
414
  /** Search models by name, provider, or capability */
327
415
  async searchModels(query) {
328
416
  const all = await this.models();
@@ -1,2 +1,2 @@
1
1
  import 'viem';
2
- export { A as AutoReplenishOptions, S as ShieldedWallet, h as SpendAuth, k as createShieldedClient, l as estimateCost, g as generateWallet, s as signSpendAuth } from './shielded-BRhsV-s-.cjs';
2
+ export { A as AutoReplenishOptions, S as ShieldedWallet, l as SpendAuth, o as createShieldedClient, p as estimateCost, g as generateWallet, s as signSpendAuth } from './shielded-xDNVqK4a.cjs';
@@ -1,2 +1,2 @@
1
1
  import 'viem';
2
- export { A as AutoReplenishOptions, S as ShieldedWallet, h as SpendAuth, k as createShieldedClient, l as estimateCost, g as generateWallet, s as signSpendAuth } from './shielded-BRhsV-s-.js';
2
+ export { A as AutoReplenishOptions, S as ShieldedWallet, l as SpendAuth, o as createShieldedClient, p as estimateCost, g as generateWallet, s as signSpendAuth } from './shielded-xDNVqK4a.js';
package/dist/shielded.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  estimateCost,
4
4
  generateWallet,
5
5
  signSpendAuth
6
- } from "./chunk-4AOQNUQ3.js";
6
+ } from "./chunk-YKLHAS4E.js";
7
7
  export {
8
8
  createShieldedClient,
9
9
  estimateCost,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/tcloud",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "TypeScript SDK and CLI for Tangle AI Cloud — decentralized LLM inference",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",