@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.
- package/dist/{chunk-VD4RNZOC.js → chunk-ADGH2R2R.js} +1 -1
- package/dist/{chunk-HL4CXKET.js → chunk-LN7XX5KG.js} +229 -29
- package/dist/{chunk-STNZT6YR.js → chunk-W7PUZZRE.js} +2 -2
- package/dist/cli.cjs +366 -53
- package/dist/cli.js +141 -27
- package/dist/{client-CcuHG7_w.d.ts → client-DskWX_BT.d.cts} +402 -13
- package/dist/{client-CcuHG7_w.d.cts → client-DskWX_BT.d.ts} +402 -13
- package/dist/index.cjs +230 -29
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +5 -3
- package/dist/instance.cjs +228 -29
- package/dist/instance.d.cts +1 -1
- package/dist/instance.d.ts +1 -1
- package/dist/instance.js +1 -1
- package/dist/shielded.cjs +228 -29
- 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
package/dist/instance.cjs
CHANGED
|
@@ -302,8 +302,10 @@ var DEFAULT_RETRY = {
|
|
|
302
302
|
retryableStatuses: [429, 500, 502, 503, 504]
|
|
303
303
|
};
|
|
304
304
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
305
|
+
var DEFAULT_PLATFORM_URL = "https://id.tangle.tools";
|
|
305
306
|
var TCloudClient = class _TCloudClient {
|
|
306
307
|
baseURL;
|
|
308
|
+
platformURL;
|
|
307
309
|
apiKey;
|
|
308
310
|
model;
|
|
309
311
|
headers;
|
|
@@ -320,6 +322,7 @@ var TCloudClient = class _TCloudClient {
|
|
|
320
322
|
static OPERATORS_TTL_MS = 5 * 60 * 1e3;
|
|
321
323
|
constructor(config = {}) {
|
|
322
324
|
this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
325
|
+
this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
|
|
323
326
|
this.apiKey = config.apiKey || process.env.TCLOUD_API_KEY;
|
|
324
327
|
this.model = config.model || "gpt-4o-mini";
|
|
325
328
|
this.privacy = config.privacy;
|
|
@@ -508,10 +511,11 @@ var TCloudClient = class _TCloudClient {
|
|
|
508
511
|
return res;
|
|
509
512
|
}
|
|
510
513
|
/**
|
|
511
|
-
* Prepare headers for chat requests — operator routing + SpendAuth
|
|
514
|
+
* Prepare headers for chat requests — operator routing + SpendAuth +
|
|
515
|
+
* bridge short-circuit headers when `options.bridge` is set.
|
|
512
516
|
* Shared between chat() and chatStream() to eliminate duplication.
|
|
513
517
|
*/
|
|
514
|
-
async _prepareChatRequest(model) {
|
|
518
|
+
async _prepareChatRequest(model, bridge) {
|
|
515
519
|
const headers = { ...this.headers };
|
|
516
520
|
if (this.spendAuthFn) {
|
|
517
521
|
const auth = await this.spendAuthFn();
|
|
@@ -528,12 +532,28 @@ var TCloudClient = class _TCloudClient {
|
|
|
528
532
|
delete headers["Authorization"];
|
|
529
533
|
}
|
|
530
534
|
}
|
|
535
|
+
if (bridge) {
|
|
536
|
+
headers["X-Bridge-Unlock"] = bridge.unlock;
|
|
537
|
+
if (bridge.resume) headers["X-Resume"] = bridge.resume;
|
|
538
|
+
if (bridge.bridgeUrl) headers["X-Bridge-Url"] = bridge.bridgeUrl;
|
|
539
|
+
if (bridge.bridgeBearer) headers["X-Bridge-Bearer"] = bridge.bridgeBearer;
|
|
540
|
+
}
|
|
531
541
|
return { headers, baseURL };
|
|
532
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Resolve the effective model string. When a bridge is set, rewrite to
|
|
545
|
+
* `bridge/<harness>/<model>` (or `bridge/<harness>` if no model).
|
|
546
|
+
*/
|
|
547
|
+
_effectiveModel(options) {
|
|
548
|
+
if (options.bridge) {
|
|
549
|
+
return options.bridge.model ? `bridge/${options.bridge.harness}/${options.bridge.model}` : `bridge/${options.bridge.harness}`;
|
|
550
|
+
}
|
|
551
|
+
return options.model || this.model;
|
|
552
|
+
}
|
|
533
553
|
/** Build the chat completions request body */
|
|
534
554
|
_chatBody(options, stream) {
|
|
535
555
|
return JSON.stringify({
|
|
536
|
-
model:
|
|
556
|
+
model: this._effectiveModel(options),
|
|
537
557
|
messages: options.messages,
|
|
538
558
|
temperature: options.temperature,
|
|
539
559
|
max_tokens: options.maxTokens,
|
|
@@ -545,13 +565,17 @@ var TCloudClient = class _TCloudClient {
|
|
|
545
565
|
response_format: options.responseFormat,
|
|
546
566
|
tools: options.tools,
|
|
547
567
|
tool_choice: options.toolChoice,
|
|
568
|
+
...options.gateway ? { gateway: options.gateway } : {},
|
|
548
569
|
...options.providerOptions
|
|
549
570
|
});
|
|
550
571
|
}
|
|
551
572
|
/** Chat completion (non-streaming) */
|
|
552
573
|
async chat(options) {
|
|
553
574
|
this.checkLimits();
|
|
554
|
-
const { headers, baseURL } = await this._prepareChatRequest(
|
|
575
|
+
const { headers, baseURL } = await this._prepareChatRequest(
|
|
576
|
+
this._effectiveModel(options),
|
|
577
|
+
options.bridge
|
|
578
|
+
);
|
|
555
579
|
const res = await this._doFetch(`${baseURL}/chat/completions`, {
|
|
556
580
|
method: "POST",
|
|
557
581
|
headers,
|
|
@@ -565,7 +589,10 @@ var TCloudClient = class _TCloudClient {
|
|
|
565
589
|
async *chatStream(options) {
|
|
566
590
|
this.checkLimits();
|
|
567
591
|
this._requestCount++;
|
|
568
|
-
const { headers, baseURL } = await this._prepareChatRequest(
|
|
592
|
+
const { headers, baseURL } = await this._prepareChatRequest(
|
|
593
|
+
this._effectiveModel(options),
|
|
594
|
+
options.bridge
|
|
595
|
+
);
|
|
569
596
|
const res = await this._doFetch(`${baseURL}/chat/completions`, {
|
|
570
597
|
method: "POST",
|
|
571
598
|
headers,
|
|
@@ -594,6 +621,24 @@ var TCloudClient = class _TCloudClient {
|
|
|
594
621
|
}
|
|
595
622
|
}
|
|
596
623
|
}
|
|
624
|
+
/**
|
|
625
|
+
* Bridge — scoped helper for a subscription-backed CLI harness behind
|
|
626
|
+
* the Tangle Router's cli-bridge. Returns a mini-client bound to
|
|
627
|
+
* (harness, unlock, resume) so you don't thread those through every
|
|
628
|
+
* call.
|
|
629
|
+
*
|
|
630
|
+
* ```ts
|
|
631
|
+
* const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
|
|
632
|
+
* await kimi.ask('review this diff…')
|
|
633
|
+
* for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
|
|
634
|
+
* ```
|
|
635
|
+
*
|
|
636
|
+
* Sessions persist across process restarts — use the same `resume` id
|
|
637
|
+
* to land on the same CLI conversation (context intact, no replay tax).
|
|
638
|
+
*/
|
|
639
|
+
bridge(cfg) {
|
|
640
|
+
return new BridgeSession(this, cfg);
|
|
641
|
+
}
|
|
597
642
|
/** Convenience: send a single message and get the text response */
|
|
598
643
|
async ask(message, modelOrOptions) {
|
|
599
644
|
const options = typeof modelOrOptions === "string" ? { model: modelOrOptions } : modelOrOptions;
|
|
@@ -632,43 +677,89 @@ var TCloudClient = class _TCloudClient {
|
|
|
632
677
|
const apiRoot = this.baseURL.replace(/\/v1$/, "");
|
|
633
678
|
return this._fetch(`${apiRoot}/api/operators`);
|
|
634
679
|
}
|
|
680
|
+
// ── Billing (via id.tangle.tools) ──
|
|
635
681
|
/** Get credit balance */
|
|
636
682
|
async credits() {
|
|
637
|
-
const
|
|
638
|
-
return
|
|
683
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/billing/balance`);
|
|
684
|
+
return data;
|
|
639
685
|
}
|
|
640
|
-
/** Add credits */
|
|
686
|
+
/** Add credits via Stripe checkout. Returns the checkout URL. */
|
|
641
687
|
async addCredits(amount) {
|
|
642
|
-
const
|
|
643
|
-
return this._fetch(`${apiRoot}/api/billing`, {
|
|
688
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/billing/topup`, {
|
|
644
689
|
method: "POST",
|
|
645
690
|
body: JSON.stringify({ amount })
|
|
646
691
|
});
|
|
692
|
+
return data;
|
|
647
693
|
}
|
|
648
|
-
/**
|
|
649
|
-
async
|
|
650
|
-
const
|
|
651
|
-
return
|
|
694
|
+
/** Get transaction history */
|
|
695
|
+
async transactions(limit = 50) {
|
|
696
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/billing/transactions?limit=${limit}`);
|
|
697
|
+
return data;
|
|
698
|
+
}
|
|
699
|
+
// ── API Keys (via id.tangle.tools) ──
|
|
700
|
+
/**
|
|
701
|
+
* Create a new API key.
|
|
702
|
+
* When called with an API key (not session), the new key is automatically
|
|
703
|
+
* a child of the calling key — enabling hierarchical key delegation.
|
|
704
|
+
*
|
|
705
|
+
* Pass `parentKeyId` explicitly to create a child of a specific key.
|
|
706
|
+
* Child keys inherit the parent's product scope, allowedModels, and rpmLimit
|
|
707
|
+
* if not specified. Budget cannot exceed the parent's remaining budget.
|
|
708
|
+
*/
|
|
709
|
+
async createKey(opts) {
|
|
710
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys`, {
|
|
652
711
|
method: "POST",
|
|
653
|
-
body: JSON.stringify(
|
|
712
|
+
body: JSON.stringify(opts)
|
|
654
713
|
});
|
|
714
|
+
return data;
|
|
655
715
|
}
|
|
656
|
-
/**
|
|
657
|
-
async
|
|
658
|
-
const
|
|
659
|
-
return
|
|
716
|
+
/** Get a single API key by ID */
|
|
717
|
+
async getKey(id) {
|
|
718
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys/${id}`);
|
|
719
|
+
return data;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* List API keys.
|
|
723
|
+
* Pass `children: true` to list child keys of the calling API key.
|
|
724
|
+
*/
|
|
725
|
+
async keys(opts) {
|
|
726
|
+
const q = opts?.children ? "?children=true" : "";
|
|
727
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys${q}`);
|
|
728
|
+
return data;
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Update an API key's limits.
|
|
732
|
+
* Can adjust budget, allowedModels, rpmLimit, expiresAt, and name.
|
|
733
|
+
*/
|
|
734
|
+
async updateKey(id, updates) {
|
|
735
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys/${id}`, {
|
|
736
|
+
method: "PATCH",
|
|
737
|
+
body: JSON.stringify(updates)
|
|
738
|
+
});
|
|
739
|
+
return data;
|
|
660
740
|
}
|
|
661
|
-
/** Revoke an API key */
|
|
741
|
+
/** Revoke an API key. If the key has children, they are also revoked recursively. */
|
|
662
742
|
async revokeKey(id) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
743
|
+
await this._fetch(`${this.platformURL}/v1/keys/${id}`, { method: "DELETE" });
|
|
744
|
+
}
|
|
745
|
+
/** Rotate an API key — creates new key with same config, revokes old */
|
|
746
|
+
async rotateKey(id) {
|
|
747
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/keys/${id}/rotate`, { method: "POST" });
|
|
748
|
+
return data;
|
|
749
|
+
}
|
|
750
|
+
// ── Projects (via id.tangle.tools) ──
|
|
751
|
+
/** Create a project for usage attribution */
|
|
752
|
+
async createProject(name, product) {
|
|
753
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/projects`, {
|
|
754
|
+
method: "POST",
|
|
755
|
+
body: JSON.stringify({ name, product })
|
|
756
|
+
});
|
|
757
|
+
return data;
|
|
758
|
+
}
|
|
759
|
+
/** List projects */
|
|
760
|
+
async projects() {
|
|
761
|
+
const { data } = await this._fetch(`${this.platformURL}/v1/projects`);
|
|
762
|
+
return data;
|
|
672
763
|
}
|
|
673
764
|
/** Generate embeddings */
|
|
674
765
|
async embeddings(options) {
|
|
@@ -979,6 +1070,61 @@ var TCloudClient = class _TCloudClient {
|
|
|
979
1070
|
};
|
|
980
1071
|
});
|
|
981
1072
|
}
|
|
1073
|
+
// ── Eval ──────────────────────────────────────────────────────────────
|
|
1074
|
+
get _apiRoot() {
|
|
1075
|
+
return this.baseURL.replace(/\/v1$/, "");
|
|
1076
|
+
}
|
|
1077
|
+
async eval(opts) {
|
|
1078
|
+
return this._request(`${this._apiRoot}/api/eval`, { method: "POST", body: JSON.stringify(opts) });
|
|
1079
|
+
}
|
|
1080
|
+
async createSuite(opts) {
|
|
1081
|
+
return this._request(`${this._apiRoot}/api/eval/suites`, { method: "POST", body: JSON.stringify(opts) });
|
|
1082
|
+
}
|
|
1083
|
+
async listSuites() {
|
|
1084
|
+
return this._fetch(`${this._apiRoot}/api/eval/suites`);
|
|
1085
|
+
}
|
|
1086
|
+
async runSuite(suiteId, opts) {
|
|
1087
|
+
return this._request(`${this._apiRoot}/api/eval/suites/${suiteId}/runs`, { method: "POST", body: JSON.stringify(opts || {}) });
|
|
1088
|
+
}
|
|
1089
|
+
async listRuns(suiteId) {
|
|
1090
|
+
return this._fetch(`${this._apiRoot}/api/eval/suites/${suiteId}/runs`);
|
|
1091
|
+
}
|
|
1092
|
+
async getRun(runId) {
|
|
1093
|
+
return this._fetch(`${this._apiRoot}/api/eval/runs/${runId}`);
|
|
1094
|
+
}
|
|
1095
|
+
async setBaseline(runId) {
|
|
1096
|
+
await this._request(`${this._apiRoot}/api/eval/runs/${runId}`, { method: "PATCH", body: JSON.stringify({ baseline: true }) });
|
|
1097
|
+
}
|
|
1098
|
+
// ── Sandbox ──────────────────────────────────────────────────────────
|
|
1099
|
+
async sandboxPricing(opts) {
|
|
1100
|
+
const p = new URLSearchParams();
|
|
1101
|
+
if (opts?.cpu) p.set("cpu", String(opts.cpu));
|
|
1102
|
+
if (opts?.ram) p.set("ram", String(opts.ram));
|
|
1103
|
+
if (opts?.disk) p.set("disk", String(opts.disk));
|
|
1104
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/pricing?${p}`);
|
|
1105
|
+
}
|
|
1106
|
+
async sandboxStatus() {
|
|
1107
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/link-key`);
|
|
1108
|
+
}
|
|
1109
|
+
async sandboxProvision() {
|
|
1110
|
+
return this._request(`${this._apiRoot}/api/sandbox/provision`, { method: "POST" });
|
|
1111
|
+
}
|
|
1112
|
+
async sandboxCreate(opts) {
|
|
1113
|
+
return this._request(`${this._apiRoot}/api/sandbox/sessions`, { method: "POST", body: JSON.stringify(opts) });
|
|
1114
|
+
}
|
|
1115
|
+
async sandboxList() {
|
|
1116
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/sessions`);
|
|
1117
|
+
}
|
|
1118
|
+
async sandboxStats(sandboxId) {
|
|
1119
|
+
return this._fetch(`${this._apiRoot}/api/sandbox/stats/${sandboxId}`);
|
|
1120
|
+
}
|
|
1121
|
+
async sandboxDestroy(sessionId) {
|
|
1122
|
+
return this._request(`${this._apiRoot}/api/sandbox/sessions/${sessionId}`, { method: "DELETE" });
|
|
1123
|
+
}
|
|
1124
|
+
// ── User Info ────────────────────────────────────────────────────────
|
|
1125
|
+
async userInfo() {
|
|
1126
|
+
return this._fetch(`${this._apiRoot}/api/auth/userinfo`);
|
|
1127
|
+
}
|
|
982
1128
|
};
|
|
983
1129
|
var ALL_TIERS = [
|
|
984
1130
|
{ name: "cpu-only", cpu: 4, ramGb: 16, gpu: 0, tee: false },
|
|
@@ -989,6 +1135,59 @@ var ALL_TIERS = [
|
|
|
989
1135
|
{ name: "max-gpu", cpu: 64, ramGb: 256, gpu: 4, tee: false },
|
|
990
1136
|
{ name: "max-gpu-tee", cpu: 64, ramGb: 256, gpu: 4, tee: true }
|
|
991
1137
|
];
|
|
1138
|
+
var BridgeSession = class _BridgeSession {
|
|
1139
|
+
constructor(client, cfg) {
|
|
1140
|
+
this.client = client;
|
|
1141
|
+
this.cfg = cfg;
|
|
1142
|
+
}
|
|
1143
|
+
/** Full chat completion (non-streaming). */
|
|
1144
|
+
async chat(options) {
|
|
1145
|
+
return this.client.chat({ ...options, bridge: this.cfg });
|
|
1146
|
+
}
|
|
1147
|
+
/** Stream OpenAI chat.completion.chunks. */
|
|
1148
|
+
chatStream(options) {
|
|
1149
|
+
return this.client.chatStream({ ...options, bridge: this.cfg });
|
|
1150
|
+
}
|
|
1151
|
+
/** One-shot: send a string, get the assistant text. */
|
|
1152
|
+
async ask(message, extra) {
|
|
1153
|
+
const completion = await this.chat({
|
|
1154
|
+
messages: [{ role: "user", content: message }],
|
|
1155
|
+
...extra
|
|
1156
|
+
});
|
|
1157
|
+
return completion.choices[0]?.message?.content || "";
|
|
1158
|
+
}
|
|
1159
|
+
/** One-shot: send a string, stream text deltas. */
|
|
1160
|
+
async *stream(message, extra) {
|
|
1161
|
+
for await (const chunk of this.chatStream({
|
|
1162
|
+
messages: [{ role: "user", content: message }],
|
|
1163
|
+
...extra
|
|
1164
|
+
})) {
|
|
1165
|
+
const content = chunk.choices?.[0]?.delta?.content;
|
|
1166
|
+
if (content) yield content;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
/** Turn-based: send full message history, get assistant text. */
|
|
1170
|
+
async turn(messages, extra) {
|
|
1171
|
+
const completion = await this.chat({ messages, ...extra });
|
|
1172
|
+
return completion.choices[0]?.message?.content || "";
|
|
1173
|
+
}
|
|
1174
|
+
/** Clone with a new resume id — same harness, different logical conversation. */
|
|
1175
|
+
withResume(resume) {
|
|
1176
|
+
return new _BridgeSession(this.client, { ...this.cfg, resume });
|
|
1177
|
+
}
|
|
1178
|
+
/** Clone with a different model inside the same harness. */
|
|
1179
|
+
withModel(model) {
|
|
1180
|
+
return new _BridgeSession(this.client, { ...this.cfg, model });
|
|
1181
|
+
}
|
|
1182
|
+
/** The effective model id that will land on the router (`bridge/<harness>/<model>`). */
|
|
1183
|
+
get model() {
|
|
1184
|
+
return this.cfg.model ? `bridge/${this.cfg.harness}/${this.cfg.model}` : `bridge/${this.cfg.harness}`;
|
|
1185
|
+
}
|
|
1186
|
+
/** The resume id currently bound to this session, if any. */
|
|
1187
|
+
get resume() {
|
|
1188
|
+
return this.cfg.resume;
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
992
1191
|
function selectTiers(all, n) {
|
|
993
1192
|
if (n >= all.length) return [...all];
|
|
994
1193
|
if (n <= 1) return [all[0]];
|
package/dist/instance.d.cts
CHANGED
package/dist/instance.d.ts
CHANGED