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