@tangle-network/tcloud 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HL4CXKET.js → chunk-AKR7CS4P.js} +231 -30
- package/dist/{chunk-VD4RNZOC.js → chunk-MKLCBBHZ.js} +1 -1
- package/dist/{chunk-STNZT6YR.js → chunk-QNIJ7KAA.js} +2 -2
- package/dist/cli.cjs +368 -54
- package/dist/cli.js +141 -27
- package/dist/{client-CcuHG7_w.d.ts → client-_ghO89WM.d.cts} +402 -13
- package/dist/{client-CcuHG7_w.d.cts → client-_ghO89WM.d.ts} +402 -13
- package/dist/index.cjs +232 -30
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +5 -3
- package/dist/instance.cjs +230 -30
- package/dist/instance.d.cts +1 -1
- package/dist/instance.d.ts +1 -1
- package/dist/instance.js +1 -1
- package/dist/shielded.cjs +230 -30
- package/dist/shielded.d.cts +1 -1
- package/dist/shielded.d.ts +1 -1
- package/dist/shielded.js +2 -2
- package/package.json +2 -1
|
@@ -213,6 +213,7 @@ var PrivateRouter = class {
|
|
|
213
213
|
|
|
214
214
|
// src/client.ts
|
|
215
215
|
var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
|
|
216
|
+
var SDK_VERSION = "0.4.0";
|
|
216
217
|
async function proxiedFetch(privacy, url, init, streaming) {
|
|
217
218
|
if (!privacy || privacy.mode === "direct") {
|
|
218
219
|
return fetch(url, init);
|
|
@@ -259,8 +260,10 @@ var DEFAULT_RETRY = {
|
|
|
259
260
|
retryableStatuses: [429, 500, 502, 503, 504]
|
|
260
261
|
};
|
|
261
262
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
263
|
+
var DEFAULT_PLATFORM_URL = "https://id.tangle.tools";
|
|
262
264
|
var TCloudClient = class _TCloudClient {
|
|
263
265
|
baseURL;
|
|
266
|
+
platformURL;
|
|
264
267
|
apiKey;
|
|
265
268
|
model;
|
|
266
269
|
headers;
|
|
@@ -277,6 +280,7 @@ var TCloudClient = class _TCloudClient {
|
|
|
277
280
|
static OPERATORS_TTL_MS = 5 * 60 * 1e3;
|
|
278
281
|
constructor(config = {}) {
|
|
279
282
|
this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
283
|
+
this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
|
|
280
284
|
this.apiKey = config.apiKey || process.env.TCLOUD_API_KEY;
|
|
281
285
|
this.model = config.model || "gpt-4o-mini";
|
|
282
286
|
this.privacy = config.privacy;
|
|
@@ -285,7 +289,7 @@ var TCloudClient = class _TCloudClient {
|
|
|
285
289
|
this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
286
290
|
this.headers = {
|
|
287
291
|
"Content-Type": "application/json",
|
|
288
|
-
"X-Tangle-Client":
|
|
292
|
+
"X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
|
|
289
293
|
};
|
|
290
294
|
if (this.apiKey) {
|
|
291
295
|
this.headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
@@ -465,10 +469,11 @@ var TCloudClient = class _TCloudClient {
|
|
|
465
469
|
return res;
|
|
466
470
|
}
|
|
467
471
|
/**
|
|
468
|
-
* Prepare headers for chat requests — operator routing + SpendAuth
|
|
472
|
+
* Prepare headers for chat requests — operator routing + SpendAuth +
|
|
473
|
+
* bridge short-circuit headers when `options.bridge` is set.
|
|
469
474
|
* Shared between chat() and chatStream() to eliminate duplication.
|
|
470
475
|
*/
|
|
471
|
-
async _prepareChatRequest(model) {
|
|
476
|
+
async _prepareChatRequest(model, bridge) {
|
|
472
477
|
const headers = { ...this.headers };
|
|
473
478
|
if (this.spendAuthFn) {
|
|
474
479
|
const auth = await this.spendAuthFn();
|
|
@@ -485,12 +490,28 @@ var TCloudClient = class _TCloudClient {
|
|
|
485
490
|
delete headers["Authorization"];
|
|
486
491
|
}
|
|
487
492
|
}
|
|
493
|
+
if (bridge) {
|
|
494
|
+
headers["X-Bridge-Unlock"] = bridge.unlock;
|
|
495
|
+
if (bridge.resume) headers["X-Resume"] = bridge.resume;
|
|
496
|
+
if (bridge.bridgeUrl) headers["X-Bridge-Url"] = bridge.bridgeUrl;
|
|
497
|
+
if (bridge.bridgeBearer) headers["X-Bridge-Bearer"] = bridge.bridgeBearer;
|
|
498
|
+
}
|
|
488
499
|
return { headers, baseURL };
|
|
489
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Resolve the effective model string. When a bridge is set, rewrite to
|
|
503
|
+
* `bridge/<harness>/<model>` (or `bridge/<harness>` if no model).
|
|
504
|
+
*/
|
|
505
|
+
_effectiveModel(options) {
|
|
506
|
+
if (options.bridge) {
|
|
507
|
+
return options.bridge.model ? `bridge/${options.bridge.harness}/${options.bridge.model}` : `bridge/${options.bridge.harness}`;
|
|
508
|
+
}
|
|
509
|
+
return options.model || this.model;
|
|
510
|
+
}
|
|
490
511
|
/** Build the chat completions request body */
|
|
491
512
|
_chatBody(options, stream) {
|
|
492
513
|
return JSON.stringify({
|
|
493
|
-
model:
|
|
514
|
+
model: this._effectiveModel(options),
|
|
494
515
|
messages: options.messages,
|
|
495
516
|
temperature: options.temperature,
|
|
496
517
|
max_tokens: options.maxTokens,
|
|
@@ -502,13 +523,17 @@ var TCloudClient = class _TCloudClient {
|
|
|
502
523
|
response_format: options.responseFormat,
|
|
503
524
|
tools: options.tools,
|
|
504
525
|
tool_choice: options.toolChoice,
|
|
526
|
+
...options.gateway ? { gateway: options.gateway } : {},
|
|
505
527
|
...options.providerOptions
|
|
506
528
|
});
|
|
507
529
|
}
|
|
508
530
|
/** Chat completion (non-streaming) */
|
|
509
531
|
async chat(options) {
|
|
510
532
|
this.checkLimits();
|
|
511
|
-
const { headers, baseURL } = await this._prepareChatRequest(
|
|
533
|
+
const { headers, baseURL } = await this._prepareChatRequest(
|
|
534
|
+
this._effectiveModel(options),
|
|
535
|
+
options.bridge
|
|
536
|
+
);
|
|
512
537
|
const res = await this._doFetch(`${baseURL}/chat/completions`, {
|
|
513
538
|
method: "POST",
|
|
514
539
|
headers,
|
|
@@ -522,7 +547,10 @@ var TCloudClient = class _TCloudClient {
|
|
|
522
547
|
async *chatStream(options) {
|
|
523
548
|
this.checkLimits();
|
|
524
549
|
this._requestCount++;
|
|
525
|
-
const { headers, baseURL } = await this._prepareChatRequest(
|
|
550
|
+
const { headers, baseURL } = await this._prepareChatRequest(
|
|
551
|
+
this._effectiveModel(options),
|
|
552
|
+
options.bridge
|
|
553
|
+
);
|
|
526
554
|
const res = await this._doFetch(`${baseURL}/chat/completions`, {
|
|
527
555
|
method: "POST",
|
|
528
556
|
headers,
|
|
@@ -551,6 +579,24 @@ var TCloudClient = class _TCloudClient {
|
|
|
551
579
|
}
|
|
552
580
|
}
|
|
553
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Bridge — scoped helper for a subscription-backed CLI harness behind
|
|
584
|
+
* the Tangle Router's cli-bridge. Returns a mini-client bound to
|
|
585
|
+
* (harness, unlock, resume) so you don't thread those through every
|
|
586
|
+
* call.
|
|
587
|
+
*
|
|
588
|
+
* ```ts
|
|
589
|
+
* const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
|
|
590
|
+
* await kimi.ask('review this diff…')
|
|
591
|
+
* for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
|
|
592
|
+
* ```
|
|
593
|
+
*
|
|
594
|
+
* Sessions persist across process restarts — use the same `resume` id
|
|
595
|
+
* to land on the same CLI conversation (context intact, no replay tax).
|
|
596
|
+
*/
|
|
597
|
+
bridge(cfg) {
|
|
598
|
+
return new BridgeSession(this, cfg);
|
|
599
|
+
}
|
|
554
600
|
/** Convenience: send a single message and get the text response */
|
|
555
601
|
async ask(message, modelOrOptions) {
|
|
556
602
|
const options = typeof modelOrOptions === "string" ? { model: modelOrOptions } : modelOrOptions;
|
|
@@ -589,43 +635,89 @@ var TCloudClient = class _TCloudClient {
|
|
|
589
635
|
const apiRoot = this.baseURL.replace(/\/v1$/, "");
|
|
590
636
|
return this._fetch(`${apiRoot}/api/operators`);
|
|
591
637
|
}
|
|
638
|
+
// ── Billing (via id.tangle.tools) ──
|
|
592
639
|
/** Get credit balance */
|
|
593
640
|
async credits() {
|
|
594
|
-
const
|
|
595
|
-
return
|
|
641
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/billing/balance`);
|
|
642
|
+
return data;
|
|
596
643
|
}
|
|
597
|
-
/** Add credits */
|
|
644
|
+
/** Add credits via Stripe checkout. Returns the checkout URL. */
|
|
598
645
|
async addCredits(amount) {
|
|
599
|
-
const
|
|
600
|
-
return this._fetch(`${apiRoot}/api/billing`, {
|
|
646
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/billing/topup`, {
|
|
601
647
|
method: "POST",
|
|
602
648
|
body: JSON.stringify({ amount })
|
|
603
649
|
});
|
|
650
|
+
return data;
|
|
604
651
|
}
|
|
605
|
-
/**
|
|
606
|
-
async
|
|
607
|
-
const
|
|
608
|
-
return
|
|
652
|
+
/** Get transaction history */
|
|
653
|
+
async transactions(limit = 50) {
|
|
654
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/billing/transactions?limit=${limit}`);
|
|
655
|
+
return data;
|
|
656
|
+
}
|
|
657
|
+
// ── API Keys (via id.tangle.tools) ──
|
|
658
|
+
/**
|
|
659
|
+
* Create a new API key.
|
|
660
|
+
* When called with an API key (not session), the new key is automatically
|
|
661
|
+
* a child of the calling key — enabling hierarchical key delegation.
|
|
662
|
+
*
|
|
663
|
+
* Pass `parentKeyId` explicitly to create a child of a specific key.
|
|
664
|
+
* Child keys inherit the parent's product scope, allowedModels, and rpmLimit
|
|
665
|
+
* if not specified. Budget cannot exceed the parent's remaining budget.
|
|
666
|
+
*/
|
|
667
|
+
async createKey(opts) {
|
|
668
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys`, {
|
|
609
669
|
method: "POST",
|
|
610
|
-
body: JSON.stringify(
|
|
670
|
+
body: JSON.stringify(opts)
|
|
611
671
|
});
|
|
672
|
+
return data;
|
|
612
673
|
}
|
|
613
|
-
/**
|
|
614
|
-
async
|
|
615
|
-
const
|
|
616
|
-
return
|
|
674
|
+
/** Get a single API key by ID */
|
|
675
|
+
async getKey(id) {
|
|
676
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys/${id}`);
|
|
677
|
+
return data;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* List API keys.
|
|
681
|
+
* Pass `children: true` to list child keys of the calling API key.
|
|
682
|
+
*/
|
|
683
|
+
async keys(opts) {
|
|
684
|
+
const q = opts?.children ? "?children=true" : "";
|
|
685
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys${q}`);
|
|
686
|
+
return data;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Update an API key's limits.
|
|
690
|
+
* Can adjust budget, allowedModels, rpmLimit, expiresAt, and name.
|
|
691
|
+
*/
|
|
692
|
+
async updateKey(id, updates) {
|
|
693
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys/${id}`, {
|
|
694
|
+
method: "PATCH",
|
|
695
|
+
body: JSON.stringify(updates)
|
|
696
|
+
});
|
|
697
|
+
return data;
|
|
617
698
|
}
|
|
618
|
-
/** Revoke an API key */
|
|
699
|
+
/** Revoke an API key. If the key has children, they are also revoked recursively. */
|
|
619
700
|
async revokeKey(id) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
701
|
+
await this._fetch(`${this.platformURL}/v1/keys/${id}`, { method: "DELETE" });
|
|
702
|
+
}
|
|
703
|
+
/** Rotate an API key — creates new key with same config, revokes old */
|
|
704
|
+
async rotateKey(id) {
|
|
705
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys/${id}/rotate`, { method: "POST" });
|
|
706
|
+
return data;
|
|
707
|
+
}
|
|
708
|
+
// ── Projects (via id.tangle.tools) ──
|
|
709
|
+
/** Create a project for usage attribution */
|
|
710
|
+
async createProject(name, product) {
|
|
711
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/projects`, {
|
|
712
|
+
method: "POST",
|
|
713
|
+
body: JSON.stringify({ name, product })
|
|
714
|
+
});
|
|
715
|
+
return data;
|
|
716
|
+
}
|
|
717
|
+
/** List projects */
|
|
718
|
+
async projects() {
|
|
719
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/projects`);
|
|
720
|
+
return data;
|
|
629
721
|
}
|
|
630
722
|
/** Generate embeddings */
|
|
631
723
|
async embeddings(options) {
|
|
@@ -936,6 +1028,61 @@ var TCloudClient = class _TCloudClient {
|
|
|
936
1028
|
};
|
|
937
1029
|
});
|
|
938
1030
|
}
|
|
1031
|
+
// ── Eval ──────────────────────────────────────────────────────────────
|
|
1032
|
+
get _apiRoot() {
|
|
1033
|
+
return this.baseURL.replace(/\/v1$/, "");
|
|
1034
|
+
}
|
|
1035
|
+
async eval(opts) {
|
|
1036
|
+
return this._request(`${this._apiRoot}/api/eval`, { method: "POST", body: JSON.stringify(opts) });
|
|
1037
|
+
}
|
|
1038
|
+
async createSuite(opts) {
|
|
1039
|
+
return this._request(`${this._apiRoot}/api/eval/suites`, { method: "POST", body: JSON.stringify(opts) });
|
|
1040
|
+
}
|
|
1041
|
+
async listSuites() {
|
|
1042
|
+
return this._fetch(`${this._apiRoot}/api/eval/suites`);
|
|
1043
|
+
}
|
|
1044
|
+
async runSuite(suiteId, opts) {
|
|
1045
|
+
return this._request(`${this._apiRoot}/api/eval/suites/${suiteId}/runs`, { method: "POST", body: JSON.stringify(opts || {}) });
|
|
1046
|
+
}
|
|
1047
|
+
async listRuns(suiteId) {
|
|
1048
|
+
return this._fetch(`${this._apiRoot}/api/eval/suites/${suiteId}/runs`);
|
|
1049
|
+
}
|
|
1050
|
+
async getRun(runId) {
|
|
1051
|
+
return this._fetch(`${this._apiRoot}/api/eval/runs/${runId}`);
|
|
1052
|
+
}
|
|
1053
|
+
async setBaseline(runId) {
|
|
1054
|
+
await this._request(`${this._apiRoot}/api/eval/runs/${runId}`, { method: "PATCH", body: JSON.stringify({ baseline: true }) });
|
|
1055
|
+
}
|
|
1056
|
+
// ── Sandbox ──────────────────────────────────────────────────────────
|
|
1057
|
+
async sandboxPricing(opts) {
|
|
1058
|
+
const p = new URLSearchParams();
|
|
1059
|
+
if (opts?.cpu) p.set("cpu", String(opts.cpu));
|
|
1060
|
+
if (opts?.ram) p.set("ram", String(opts.ram));
|
|
1061
|
+
if (opts?.disk) p.set("disk", String(opts.disk));
|
|
1062
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/pricing?${p}`);
|
|
1063
|
+
}
|
|
1064
|
+
async sandboxStatus() {
|
|
1065
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/link-key`);
|
|
1066
|
+
}
|
|
1067
|
+
async sandboxProvision() {
|
|
1068
|
+
return this._request(`${this._apiRoot}/api/sandbox/provision`, { method: "POST" });
|
|
1069
|
+
}
|
|
1070
|
+
async sandboxCreate(opts) {
|
|
1071
|
+
return this._request(`${this._apiRoot}/api/sandbox/sessions`, { method: "POST", body: JSON.stringify(opts) });
|
|
1072
|
+
}
|
|
1073
|
+
async sandboxList() {
|
|
1074
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/sessions`);
|
|
1075
|
+
}
|
|
1076
|
+
async sandboxStats(sandboxId) {
|
|
1077
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/stats/${sandboxId}`);
|
|
1078
|
+
}
|
|
1079
|
+
async sandboxDestroy(sessionId) {
|
|
1080
|
+
return this._request(`${this._apiRoot}/api/sandbox/sessions/${sessionId}`, { method: "DELETE" });
|
|
1081
|
+
}
|
|
1082
|
+
// ── User Info ────────────────────────────────────────────────────────
|
|
1083
|
+
async userInfo() {
|
|
1084
|
+
return this._fetch(`${this._apiRoot}/api/auth/userinfo`);
|
|
1085
|
+
}
|
|
939
1086
|
};
|
|
940
1087
|
var ALL_TIERS = [
|
|
941
1088
|
{ name: "cpu-only", cpu: 4, ramGb: 16, gpu: 0, tee: false },
|
|
@@ -946,6 +1093,59 @@ var ALL_TIERS = [
|
|
|
946
1093
|
{ name: "max-gpu", cpu: 64, ramGb: 256, gpu: 4, tee: false },
|
|
947
1094
|
{ name: "max-gpu-tee", cpu: 64, ramGb: 256, gpu: 4, tee: true }
|
|
948
1095
|
];
|
|
1096
|
+
var BridgeSession = class _BridgeSession {
|
|
1097
|
+
constructor(client, cfg) {
|
|
1098
|
+
this.client = client;
|
|
1099
|
+
this.cfg = cfg;
|
|
1100
|
+
}
|
|
1101
|
+
/** Full chat completion (non-streaming). */
|
|
1102
|
+
async chat(options) {
|
|
1103
|
+
return this.client.chat({ ...options, bridge: this.cfg });
|
|
1104
|
+
}
|
|
1105
|
+
/** Stream OpenAI chat.completion.chunks. */
|
|
1106
|
+
chatStream(options) {
|
|
1107
|
+
return this.client.chatStream({ ...options, bridge: this.cfg });
|
|
1108
|
+
}
|
|
1109
|
+
/** One-shot: send a string, get the assistant text. */
|
|
1110
|
+
async ask(message, extra) {
|
|
1111
|
+
const completion = await this.chat({
|
|
1112
|
+
messages: [{ role: "user", content: message }],
|
|
1113
|
+
...extra
|
|
1114
|
+
});
|
|
1115
|
+
return completion.choices[0]?.message?.content || "";
|
|
1116
|
+
}
|
|
1117
|
+
/** One-shot: send a string, stream text deltas. */
|
|
1118
|
+
async *stream(message, extra) {
|
|
1119
|
+
for await (const chunk of this.chatStream({
|
|
1120
|
+
messages: [{ role: "user", content: message }],
|
|
1121
|
+
...extra
|
|
1122
|
+
})) {
|
|
1123
|
+
const content = chunk.choices?.[0]?.delta?.content;
|
|
1124
|
+
if (content) yield content;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
/** Turn-based: send full message history, get assistant text. */
|
|
1128
|
+
async turn(messages, extra) {
|
|
1129
|
+
const completion = await this.chat({ messages, ...extra });
|
|
1130
|
+
return completion.choices[0]?.message?.content || "";
|
|
1131
|
+
}
|
|
1132
|
+
/** Clone with a new resume id — same harness, different logical conversation. */
|
|
1133
|
+
withResume(resume) {
|
|
1134
|
+
return new _BridgeSession(this.client, { ...this.cfg, resume });
|
|
1135
|
+
}
|
|
1136
|
+
/** Clone with a different model inside the same harness. */
|
|
1137
|
+
withModel(model) {
|
|
1138
|
+
return new _BridgeSession(this.client, { ...this.cfg, model });
|
|
1139
|
+
}
|
|
1140
|
+
/** The effective model id that will land on the router (`bridge/<harness>/<model>`). */
|
|
1141
|
+
get model() {
|
|
1142
|
+
return this.cfg.model ? `bridge/${this.cfg.harness}/${this.cfg.model}` : `bridge/${this.cfg.harness}`;
|
|
1143
|
+
}
|
|
1144
|
+
/** The resume id currently bound to this session, if any. */
|
|
1145
|
+
get resume() {
|
|
1146
|
+
return this.cfg.resume;
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
949
1149
|
function selectTiers(all, n) {
|
|
950
1150
|
if (n >= all.length) return [...all];
|
|
951
1151
|
if (n <= 1) return [all[0]];
|
|
@@ -972,5 +1172,6 @@ var TCloudError = class extends Error {
|
|
|
972
1172
|
export {
|
|
973
1173
|
PrivateRouter,
|
|
974
1174
|
TCloudClient,
|
|
1175
|
+
BridgeSession,
|
|
975
1176
|
TCloudError
|
|
976
1177
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createShieldedClient,
|
|
3
3
|
generateWallet
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MKLCBBHZ.js";
|
|
5
5
|
import {
|
|
6
6
|
TCloudClient
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-AKR7CS4P.js";
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
10
|
var TCloud = class _TCloud extends TCloudClient {
|