@tangle-network/tcloud 0.4.12 → 0.4.14
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 +13 -11
- package/dist/{chunk-THOMQXU5.js → chunk-26M4HGWE.js} +1 -1
- package/dist/chunk-GHMW4RWJ.js +16 -0
- package/dist/{chunk-U4VOGRVW.js → chunk-LUJXMUH5.js} +20 -0
- package/dist/{chunk-UBUCUSCF.js → chunk-ZJCWJGPM.js} +2 -2
- package/dist/cli.cjs +277 -23
- package/dist/cli.js +13 -15
- package/dist/{client-CaD5Oal0.d.ts → client-CaPP4njg.d.cts} +54 -1
- package/dist/{client-CaD5Oal0.d.cts → client-CaPP4njg.d.ts} +54 -1
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/instance.cjs +20 -0
- package/dist/instance.d.cts +1 -1
- package/dist/instance.d.ts +1 -1
- package/dist/instance.js +1 -1
- package/dist/mcp.cjs +254 -0
- package/dist/mcp.d.cts +27 -0
- package/dist/mcp.d.ts +27 -0
- package/dist/mcp.js +207 -0
- package/dist/shielded.cjs +20 -0
- package/dist/shielded.d.cts +1 -1
- package/dist/shielded.d.ts +1 -1
- package/dist/shielded.js +2 -2
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# tcloud
|
|
2
2
|
|
|
3
|
-
TypeScript SDK and CLI for [Tangle
|
|
3
|
+
TypeScript SDK and CLI for [Tangle Router](https://router.tangle.tools): model routing, sandbox-backed agent calls, operator routing, 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
|
|
|
@@ -37,21 +37,23 @@ Zero framework dependencies. Pure `fetch` + SSE. Works in Node.js, Deno, Bun, an
|
|
|
37
37
|
## Installation
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
npm install tcloud
|
|
40
|
+
npm install @tangle-network/tcloud
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Or run the CLI directly:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npx tcloud chat "What is Tangle?"
|
|
46
|
+
npx @tangle-network/tcloud chat "What is Tangle?"
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
Do not install unscoped `tcloud`. It is unrelated to Tangle.
|
|
50
|
+
|
|
49
51
|
## SDK
|
|
50
52
|
|
|
51
53
|
### Quick Start
|
|
52
54
|
|
|
53
55
|
```ts
|
|
54
|
-
import { TCloud } from 'tcloud'
|
|
56
|
+
import { TCloud } from '@tangle-network/tcloud'
|
|
55
57
|
|
|
56
58
|
// Set model at client creation — explicit and consistent.
|
|
57
59
|
const client = new TCloud({
|
|
@@ -159,7 +161,7 @@ console.log(completion.choices[0].message.content)
|
|
|
159
161
|
Anonymous inference with no API key. Uses EIP-712 SpendAuth signatures — the operator verifies payment without learning your identity.
|
|
160
162
|
|
|
161
163
|
```ts
|
|
162
|
-
import { TCloud } from 'tcloud'
|
|
164
|
+
import { TCloud } from '@tangle-network/tcloud'
|
|
163
165
|
|
|
164
166
|
const client = TCloud.shielded()
|
|
165
167
|
const answer = await client.ask('Hello from the shadows')
|
|
@@ -361,10 +363,10 @@ tcloud auth status # Check current auth
|
|
|
361
363
|
### Chat
|
|
362
364
|
|
|
363
365
|
```bash
|
|
364
|
-
tcloud chat "Explain zero-knowledge proofs"
|
|
365
|
-
tcloud chat -m meta-llama/llama-4-maverick "Hello"
|
|
366
|
-
tcloud chat --private "Anonymous request" # ShieldedCredits mode
|
|
367
|
-
tcloud chat # Interactive mode
|
|
366
|
+
npx @tangle-network/tcloud chat "Explain zero-knowledge proofs"
|
|
367
|
+
npx @tangle-network/tcloud chat -m meta-llama/llama-4-maverick "Hello"
|
|
368
|
+
npx @tangle-network/tcloud chat --private "Anonymous request" # ShieldedCredits mode
|
|
369
|
+
npx @tangle-network/tcloud chat # Interactive mode
|
|
368
370
|
```
|
|
369
371
|
|
|
370
372
|
### Browse
|
|
@@ -409,8 +411,8 @@ tcloud config --model gpt-4o-mini
|
|
|
409
411
|
Environment variables:
|
|
410
412
|
- `TANGLE_API_KEY` — API key (primary). One key for router + sandbox + all Tangle products.
|
|
411
413
|
- `TCLOUD_API_KEY` — Deprecated alias, still honored for backwards compatibility.
|
|
412
|
-
- `
|
|
413
|
-
- `
|
|
414
|
+
- `TANGLE_ROUTER_URL` — Override CLI router URL.
|
|
415
|
+
- `TCLOUD_API_URL` — Deprecated CLI router URL alias.
|
|
414
416
|
|
|
415
417
|
## OpenAI SDK Compatibility
|
|
416
418
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/version.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
function packageVersion() {
|
|
4
|
+
try {
|
|
5
|
+
const packageJson = JSON.parse(
|
|
6
|
+
fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
7
|
+
);
|
|
8
|
+
if (typeof packageJson.version === "string") return packageJson.version;
|
|
9
|
+
} catch {
|
|
10
|
+
}
|
|
11
|
+
return "0.0.0";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
packageVersion
|
|
16
|
+
};
|
|
@@ -998,6 +998,26 @@ var TCloudClient = class _TCloudClient {
|
|
|
998
998
|
})
|
|
999
999
|
});
|
|
1000
1000
|
}
|
|
1001
|
+
/** Run a multi-step deep-research task through Tangle Router billing and
|
|
1002
|
+
* provider routing (POST /v1/research). Slower and costlier than `search` —
|
|
1003
|
+
* the provider synthesizes an answer over many fetches. Pick depth with
|
|
1004
|
+
* `effort` (provider-specific vocabulary; see {@link ResearchOptions.effort}). */
|
|
1005
|
+
async research(options) {
|
|
1006
|
+
return this._request(`${this.baseURL}/research`, {
|
|
1007
|
+
method: "POST",
|
|
1008
|
+
body: JSON.stringify({
|
|
1009
|
+
query: options.query,
|
|
1010
|
+
provider: options.provider,
|
|
1011
|
+
model: options.model,
|
|
1012
|
+
effort: options.effort,
|
|
1013
|
+
maxResults: options.maxResults,
|
|
1014
|
+
searchRecency: options.searchRecency,
|
|
1015
|
+
includeDomains: options.includeDomains,
|
|
1016
|
+
excludeDomains: options.excludeDomains,
|
|
1017
|
+
outputSchema: options.outputSchema
|
|
1018
|
+
})
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1001
1021
|
/** Text-to-speech */
|
|
1002
1022
|
async speech(options) {
|
|
1003
1023
|
const res = await this._requestRaw(`${this.baseURL}/audio/speech`, {
|
package/dist/cli.cjs
CHANGED
|
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
9
16
|
var __copyProps = (to, from, except, desc) => {
|
|
10
17
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
18
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,6 +30,238 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
30
|
mod
|
|
24
31
|
));
|
|
25
32
|
|
|
33
|
+
// src/version.ts
|
|
34
|
+
function packageVersion() {
|
|
35
|
+
try {
|
|
36
|
+
const packageJson = JSON.parse(
|
|
37
|
+
fs.readFileSync(new URL("../package.json", import_meta.url), "utf-8")
|
|
38
|
+
);
|
|
39
|
+
if (typeof packageJson.version === "string") return packageJson.version;
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
return "0.0.0";
|
|
43
|
+
}
|
|
44
|
+
var fs, import_meta;
|
|
45
|
+
var init_version = __esm({
|
|
46
|
+
"src/version.ts"() {
|
|
47
|
+
"use strict";
|
|
48
|
+
fs = __toESM(require("fs"), 1);
|
|
49
|
+
import_meta = {};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// src/mcp.ts
|
|
54
|
+
var mcp_exports = {};
|
|
55
|
+
__export(mcp_exports, {
|
|
56
|
+
runMcpServer: () => runMcpServer
|
|
57
|
+
});
|
|
58
|
+
function optionalMaxResults(value) {
|
|
59
|
+
if (value == null) return void 0;
|
|
60
|
+
const n = Number(value);
|
|
61
|
+
return Number.isFinite(n) && n >= 0 ? n : void 0;
|
|
62
|
+
}
|
|
63
|
+
function requireEnum(value, allowed, label) {
|
|
64
|
+
if (value == null) return void 0;
|
|
65
|
+
if (typeof value !== "string" || !allowed.has(value)) {
|
|
66
|
+
throw new InvalidParams(`invalid ${label}: ${String(value)}`);
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
function optionalDomains(value) {
|
|
71
|
+
if (!Array.isArray(value)) return void 0;
|
|
72
|
+
const domains = value.filter((d) => typeof d === "string");
|
|
73
|
+
return domains.length ? domains : void 0;
|
|
74
|
+
}
|
|
75
|
+
async function runMcpServer(client, opts = {}) {
|
|
76
|
+
const input = opts.input ?? process.stdin;
|
|
77
|
+
const output = opts.output ?? process.stdout;
|
|
78
|
+
const rl = readline.createInterface({ input });
|
|
79
|
+
const send = (msg) => {
|
|
80
|
+
output.write(`${JSON.stringify(msg)}
|
|
81
|
+
`);
|
|
82
|
+
};
|
|
83
|
+
const ok = (id, result) => send({ jsonrpc: "2.0", id, result });
|
|
84
|
+
const fail = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
|
|
85
|
+
const toolError = (id, message) => ok(id, { content: [{ type: "text", text: message }], isError: true });
|
|
86
|
+
process.stderr.write("tcloud mcp: web_search + deep_research server ready (stdio)\n");
|
|
87
|
+
async function handleRequest(req) {
|
|
88
|
+
const { id, method, params } = req;
|
|
89
|
+
try {
|
|
90
|
+
if (method === "initialize") {
|
|
91
|
+
const requested = params?.protocolVersion ?? DEFAULT_PROTOCOL_VERSION;
|
|
92
|
+
const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requested) ? requested : DEFAULT_PROTOCOL_VERSION;
|
|
93
|
+
ok(id, {
|
|
94
|
+
protocolVersion,
|
|
95
|
+
capabilities: { tools: {} },
|
|
96
|
+
serverInfo: { name: "tangle-tcloud", version: packageVersion() }
|
|
97
|
+
});
|
|
98
|
+
} else if (method === "tools/list") {
|
|
99
|
+
ok(id, { tools: TOOLS });
|
|
100
|
+
} else if (method === "tools/call") {
|
|
101
|
+
const name = params?.name;
|
|
102
|
+
if (name === "web_search") {
|
|
103
|
+
await handleWebSearch(id, params?.arguments ?? {});
|
|
104
|
+
} else if (name === "deep_research") {
|
|
105
|
+
await handleDeepResearch(id, params?.arguments ?? {});
|
|
106
|
+
} else {
|
|
107
|
+
fail(id, -32602, `unknown tool: ${String(name)}`);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
fail(id, -32601, `method not found: ${String(method)}`);
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
if (e instanceof InvalidParams) {
|
|
114
|
+
fail(id, -32602, e.message);
|
|
115
|
+
} else {
|
|
116
|
+
fail(id, -32603, e instanceof Error ? e.message : String(e));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function handleWebSearch(id, args) {
|
|
121
|
+
const query = String(args.query ?? "").trim();
|
|
122
|
+
if (!query) {
|
|
123
|
+
fail(id, -32602, 'web_search requires a non-empty "query"');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const provider = requireEnum(args.provider, SEARCH_PROVIDERS, "provider");
|
|
127
|
+
const searchRecency = requireEnum(args.recency, RECENCY_WINDOWS, "recency");
|
|
128
|
+
const maxResults = optionalMaxResults(args.maxResults);
|
|
129
|
+
const includeDomains = optionalDomains(args.includeDomains);
|
|
130
|
+
const excludeDomains = optionalDomains(args.excludeDomains);
|
|
131
|
+
try {
|
|
132
|
+
const resp = await client.search({
|
|
133
|
+
query,
|
|
134
|
+
...provider ? { provider } : {},
|
|
135
|
+
...maxResults != null ? { maxResults } : {},
|
|
136
|
+
...searchRecency ? { searchRecency } : {},
|
|
137
|
+
...includeDomains ? { includeDomains } : {},
|
|
138
|
+
...excludeDomains ? { excludeDomains } : {}
|
|
139
|
+
});
|
|
140
|
+
const hits = resp.data ?? [];
|
|
141
|
+
const text = hits.length ? hits.map((h, i) => `${i + 1}. ${h.title}
|
|
142
|
+
${h.url}${h.snippet ? `
|
|
143
|
+
${h.snippet}` : ""}`).join("\n\n") : `No results for "${resp.query ?? query}".`;
|
|
144
|
+
ok(id, { content: [{ type: "text", text }] });
|
|
145
|
+
} catch (e) {
|
|
146
|
+
toolError(id, e instanceof Error ? e.message : String(e));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function handleDeepResearch(id, args) {
|
|
150
|
+
const query = String(args.query ?? "").trim();
|
|
151
|
+
if (!query) {
|
|
152
|
+
fail(id, -32602, 'deep_research requires a non-empty "query"');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const provider = requireEnum(args.provider, RESEARCH_PROVIDERS, "provider");
|
|
156
|
+
const searchRecency = requireEnum(args.searchRecency, RECENCY_WINDOWS, "searchRecency");
|
|
157
|
+
const maxResults = optionalMaxResults(args.maxResults);
|
|
158
|
+
const includeDomains = optionalDomains(args.includeDomains);
|
|
159
|
+
const excludeDomains = optionalDomains(args.excludeDomains);
|
|
160
|
+
try {
|
|
161
|
+
const resp = await client.research({
|
|
162
|
+
query,
|
|
163
|
+
...provider ? { provider } : {},
|
|
164
|
+
...typeof args.effort === "string" ? { effort: args.effort } : {},
|
|
165
|
+
...maxResults != null ? { maxResults } : {},
|
|
166
|
+
...searchRecency ? { searchRecency } : {},
|
|
167
|
+
...includeDomains ? { includeDomains } : {},
|
|
168
|
+
...excludeDomains ? { excludeDomains } : {},
|
|
169
|
+
...args.outputSchema !== void 0 ? { outputSchema: args.outputSchema } : {}
|
|
170
|
+
});
|
|
171
|
+
const sources = resp.results ?? [];
|
|
172
|
+
const sourceList = sources.length ? `
|
|
173
|
+
|
|
174
|
+
Sources:
|
|
175
|
+
${sources.map((h, i) => `${i + 1}. ${h.title}
|
|
176
|
+
${h.url}`).join("\n")}` : "";
|
|
177
|
+
const text = `${resp.answer ?? ""}${sourceList}`.trim() || `No research result for "${resp.query ?? query}".`;
|
|
178
|
+
ok(id, { content: [{ type: "text", text }] });
|
|
179
|
+
} catch (e) {
|
|
180
|
+
toolError(id, e instanceof Error ? e.message : String(e));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
for await (const line of rl) {
|
|
184
|
+
const trimmed = line.trim();
|
|
185
|
+
if (!trimmed) continue;
|
|
186
|
+
let req;
|
|
187
|
+
try {
|
|
188
|
+
req = JSON.parse(trimmed);
|
|
189
|
+
} catch {
|
|
190
|
+
send({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } });
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (req.id === void 0 || req.id === null) continue;
|
|
194
|
+
void handleRequest(req);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
var readline, SEARCH_PROVIDERS, RESEARCH_PROVIDERS, RECENCY_WINDOWS, SUPPORTED_PROTOCOL_VERSIONS, DEFAULT_PROTOCOL_VERSION, DOMAIN_FILTER_SCHEMA, TOOLS, InvalidParams;
|
|
198
|
+
var init_mcp = __esm({
|
|
199
|
+
"src/mcp.ts"() {
|
|
200
|
+
"use strict";
|
|
201
|
+
readline = __toESM(require("readline"), 1);
|
|
202
|
+
init_version();
|
|
203
|
+
SEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily", "brave"]);
|
|
204
|
+
RESEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily"]);
|
|
205
|
+
RECENCY_WINDOWS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
|
|
206
|
+
SUPPORTED_PROTOCOL_VERSIONS = /* @__PURE__ */ new Set(["2025-06-18", "2025-03-26"]);
|
|
207
|
+
DEFAULT_PROTOCOL_VERSION = "2025-06-18";
|
|
208
|
+
DOMAIN_FILTER_SCHEMA = {
|
|
209
|
+
type: "array",
|
|
210
|
+
items: { type: "string" }
|
|
211
|
+
};
|
|
212
|
+
TOOLS = [
|
|
213
|
+
{
|
|
214
|
+
name: "web_search",
|
|
215
|
+
description: "Search the web via the Tangle router and return live results (title, url, snippet). Use it to find primary sources and to VERIFY that a citation (paper, PMID/DOI, patent, fact) actually exists before relying on it.",
|
|
216
|
+
inputSchema: {
|
|
217
|
+
type: "object",
|
|
218
|
+
properties: {
|
|
219
|
+
query: { type: "string", description: "The search query." },
|
|
220
|
+
provider: {
|
|
221
|
+
type: "string",
|
|
222
|
+
description: "Optional provider: exa | parallel | perplexity | tavily | brave | you."
|
|
223
|
+
},
|
|
224
|
+
maxResults: { type: "number", description: "Optional max number of results." },
|
|
225
|
+
recency: { type: "string", description: "Optional recency window: day | week | month | year." },
|
|
226
|
+
includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict results to these domains." },
|
|
227
|
+
excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop results from these domains." }
|
|
228
|
+
},
|
|
229
|
+
required: ["query"]
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: "deep_research",
|
|
234
|
+
description: 'Run a multi-step DEEP RESEARCH task via the Tangle router: the provider reads many sources and returns one synthesized answer with citations. Slower and costlier than web_search \u2014 use it for questions that need cross-source synthesis (current API/version landscapes, comparisons, "state of X"), not single-fact lookups.',
|
|
235
|
+
inputSchema: {
|
|
236
|
+
type: "object",
|
|
237
|
+
properties: {
|
|
238
|
+
query: { type: "string", description: "The research question." },
|
|
239
|
+
provider: {
|
|
240
|
+
type: "string",
|
|
241
|
+
description: "Optional provider: you | exa | perplexity | tavily | parallel."
|
|
242
|
+
},
|
|
243
|
+
effort: {
|
|
244
|
+
type: "string",
|
|
245
|
+
description: "Optional depth/cost dial (provider-specific): you lite|standard|deep|exhaustive \xB7 perplexity minimal|low|medium|high \xB7 exa deep-lite|deep|deep-reasoning \xB7 tavily mini|pro|auto \xB7 parallel lite|base|core|pro|ultra."
|
|
246
|
+
},
|
|
247
|
+
maxResults: { type: "number", description: "Optional max number of supporting sources." },
|
|
248
|
+
searchRecency: { type: "string", description: "Optional recency window: day | week | month | year." },
|
|
249
|
+
includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict sources to these domains." },
|
|
250
|
+
excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop sources from these domains." },
|
|
251
|
+
outputSchema: {
|
|
252
|
+
type: "object",
|
|
253
|
+
description: "Optional JSON schema requesting structured output from the provider."
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
required: ["query"]
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
];
|
|
260
|
+
InvalidParams = class extends Error {
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
26
265
|
// src/cli.ts
|
|
27
266
|
var import_commander = require("commander");
|
|
28
267
|
|
|
@@ -1026,6 +1265,26 @@ var TCloudClient = class _TCloudClient {
|
|
|
1026
1265
|
})
|
|
1027
1266
|
});
|
|
1028
1267
|
}
|
|
1268
|
+
/** Run a multi-step deep-research task through Tangle Router billing and
|
|
1269
|
+
* provider routing (POST /v1/research). Slower and costlier than `search` —
|
|
1270
|
+
* the provider synthesizes an answer over many fetches. Pick depth with
|
|
1271
|
+
* `effort` (provider-specific vocabulary; see {@link ResearchOptions.effort}). */
|
|
1272
|
+
async research(options) {
|
|
1273
|
+
return this._request(`${this.baseURL}/research`, {
|
|
1274
|
+
method: "POST",
|
|
1275
|
+
body: JSON.stringify({
|
|
1276
|
+
query: options.query,
|
|
1277
|
+
provider: options.provider,
|
|
1278
|
+
model: options.model,
|
|
1279
|
+
effort: options.effort,
|
|
1280
|
+
maxResults: options.maxResults,
|
|
1281
|
+
searchRecency: options.searchRecency,
|
|
1282
|
+
includeDomains: options.includeDomains,
|
|
1283
|
+
excludeDomains: options.excludeDomains,
|
|
1284
|
+
outputSchema: options.outputSchema
|
|
1285
|
+
})
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1029
1288
|
/** Text-to-speech */
|
|
1030
1289
|
async speech(options) {
|
|
1031
1290
|
const res = await this._requestRaw(`${this.baseURL}/audio/speech`, {
|
|
@@ -2007,40 +2266,40 @@ var TCloud = class _TCloud extends TCloudClient {
|
|
|
2007
2266
|
};
|
|
2008
2267
|
|
|
2009
2268
|
// src/cli.ts
|
|
2010
|
-
|
|
2269
|
+
init_version();
|
|
2270
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
2011
2271
|
var path = __toESM(require("path"), 1);
|
|
2012
|
-
var
|
|
2272
|
+
var readline2 = __toESM(require("readline"), 1);
|
|
2013
2273
|
var import_child_process = require("child_process");
|
|
2014
|
-
var import_meta = {};
|
|
2015
2274
|
var CONFIG_DIR = path.join(process.env.HOME || "~", ".tcloud");
|
|
2016
2275
|
var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
2017
2276
|
var WALLETS_FILE = path.join(CONFIG_DIR, "wallets.json");
|
|
2018
2277
|
function ensureDir() {
|
|
2019
|
-
if (!
|
|
2278
|
+
if (!fs2.existsSync(CONFIG_DIR)) fs2.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
2020
2279
|
}
|
|
2021
2280
|
function loadConfig() {
|
|
2022
2281
|
ensureDir();
|
|
2023
|
-
const fileConfig =
|
|
2282
|
+
const fileConfig = fs2.existsSync(CONFIG_FILE) ? JSON.parse(fs2.readFileSync(CONFIG_FILE, "utf-8")) : { apiUrl: "https://router.tangle.tools", defaultModel: "gpt-4o-mini", chainId: 3799 };
|
|
2024
2283
|
return {
|
|
2025
2284
|
...fileConfig,
|
|
2026
2285
|
...process.env.TANGLE_ROUTER_URL ? { apiUrl: process.env.TANGLE_ROUTER_URL.replace(/\/v1\/?$/, "") } : {},
|
|
2027
2286
|
...process.env.TCLOUD_API_URL ? { apiUrl: process.env.TCLOUD_API_URL.replace(/\/v1\/?$/, "") } : {},
|
|
2028
|
-
...process.env.
|
|
2029
|
-
...process.env.
|
|
2287
|
+
...process.env.TCLOUD_API_KEY ? { apiKey: process.env.TCLOUD_API_KEY } : {},
|
|
2288
|
+
...process.env.TANGLE_API_KEY ? { apiKey: process.env.TANGLE_API_KEY } : {}
|
|
2030
2289
|
};
|
|
2031
2290
|
}
|
|
2032
2291
|
function saveConfig(c) {
|
|
2033
2292
|
ensureDir();
|
|
2034
|
-
|
|
2293
|
+
fs2.writeFileSync(CONFIG_FILE, JSON.stringify(c, null, 2), { mode: 384 });
|
|
2035
2294
|
}
|
|
2036
2295
|
function loadWallets() {
|
|
2037
2296
|
ensureDir();
|
|
2038
|
-
if (
|
|
2297
|
+
if (fs2.existsSync(WALLETS_FILE)) return JSON.parse(fs2.readFileSync(WALLETS_FILE, "utf-8"));
|
|
2039
2298
|
return [];
|
|
2040
2299
|
}
|
|
2041
2300
|
function saveWallets(w) {
|
|
2042
2301
|
ensureDir();
|
|
2043
|
-
|
|
2302
|
+
fs2.writeFileSync(WALLETS_FILE, JSON.stringify(w, null, 2), { mode: 384 });
|
|
2044
2303
|
}
|
|
2045
2304
|
function getClient(opts) {
|
|
2046
2305
|
const config = loadConfig();
|
|
@@ -2073,16 +2332,6 @@ function teeType(value) {
|
|
|
2073
2332
|
if (!value) return void 0;
|
|
2074
2333
|
return value.toLowerCase();
|
|
2075
2334
|
}
|
|
2076
|
-
function packageVersion() {
|
|
2077
|
-
try {
|
|
2078
|
-
const packageJson = JSON.parse(
|
|
2079
|
-
fs.readFileSync(new URL("../package.json", import_meta.url), "utf-8")
|
|
2080
|
-
);
|
|
2081
|
-
if (typeof packageJson.version === "string") return packageJson.version;
|
|
2082
|
-
} catch {
|
|
2083
|
-
}
|
|
2084
|
-
return "0.0.0";
|
|
2085
|
-
}
|
|
2086
2335
|
function printJson(value) {
|
|
2087
2336
|
console.log(JSON.stringify(value, null, 2));
|
|
2088
2337
|
}
|
|
@@ -2292,7 +2541,7 @@ program.command("chat").description("Chat with a model").argument("[message]", "
|
|
|
2292
2541
|
const client = getClient({ private: opts.private });
|
|
2293
2542
|
const model = opts.model || loadConfig().defaultModel;
|
|
2294
2543
|
if (!message) {
|
|
2295
|
-
const rl =
|
|
2544
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
2296
2545
|
console.log(`tcloud chat \u2014 ${model}${opts.private ? " (private)" : ""}
|
|
2297
2546
|
Ctrl+C to exit.
|
|
2298
2547
|
`);
|
|
@@ -2382,6 +2631,11 @@ program.command("search").description("Search the web").argument("<query>", "Sea
|
|
|
2382
2631
|
process.exit(1);
|
|
2383
2632
|
}
|
|
2384
2633
|
});
|
|
2634
|
+
program.command("mcp").description('Run a Model Context Protocol (stdio) server exposing Tangle tools (web_search, deep_research). Mount with: { "command": ["tcloud", "mcp"] }').action(async () => {
|
|
2635
|
+
const { runMcpServer: runMcpServer2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
2636
|
+
const client = getClient();
|
|
2637
|
+
await runMcpServer2(client);
|
|
2638
|
+
});
|
|
2385
2639
|
program.command("image-generate").description("Generate an image").requiredOption("-p, --prompt <prompt>", "Prompt").option("-m, --model <model>", "Image model").option("--size <size>", "Output size").option("--quality <quality>", "Output quality").option("-n, --count <n>", "Number of images").option("--response-format <format>", "url or b64_json").option("--json", "Print raw JSON response").action(async (opts) => {
|
|
2386
2640
|
const client = getClient();
|
|
2387
2641
|
try {
|
|
@@ -2441,7 +2695,7 @@ program.command("speech").description("Generate speech audio").requiredOption("-
|
|
|
2441
2695
|
model: opts.model,
|
|
2442
2696
|
voice: opts.voice
|
|
2443
2697
|
});
|
|
2444
|
-
|
|
2698
|
+
fs2.writeFileSync(opts.output, Buffer.from(audio));
|
|
2445
2699
|
const result = { output: opts.output, bytes: audio.byteLength };
|
|
2446
2700
|
if (opts.json) printJson(result);
|
|
2447
2701
|
else console.log(opts.output);
|
|
@@ -2453,7 +2707,7 @@ program.command("speech").description("Generate speech audio").requiredOption("-
|
|
|
2453
2707
|
program.command("transcribe").description("Transcribe an audio file").argument("<file>", "Audio file").option("-m, --model <model>", "Transcription model").option("--language <language>", "Language hint").option("--prompt <prompt>", "Prompt hint").option("--json", "Print raw JSON response").action(async (file, opts) => {
|
|
2454
2708
|
const client = getClient();
|
|
2455
2709
|
try {
|
|
2456
|
-
const data =
|
|
2710
|
+
const data = fs2.readFileSync(file);
|
|
2457
2711
|
const blob = new Blob([data]);
|
|
2458
2712
|
const resp = await client.transcribe(blob, {
|
|
2459
2713
|
model: opts.model,
|
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
TCloud
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZJCWJGPM.js";
|
|
5
|
+
import {
|
|
6
|
+
packageVersion
|
|
7
|
+
} from "./chunk-GHMW4RWJ.js";
|
|
5
8
|
import {
|
|
6
9
|
TCloudSandbox
|
|
7
10
|
} from "./chunk-GNACB23W.js";
|
|
8
11
|
import {
|
|
9
12
|
generateWallet
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-26M4HGWE.js";
|
|
14
|
+
import "./chunk-LUJXMUH5.js";
|
|
12
15
|
|
|
13
16
|
// src/cli.ts
|
|
14
17
|
import { Command } from "commander";
|
|
@@ -29,8 +32,8 @@ function loadConfig() {
|
|
|
29
32
|
...fileConfig,
|
|
30
33
|
...process.env.TANGLE_ROUTER_URL ? { apiUrl: process.env.TANGLE_ROUTER_URL.replace(/\/v1\/?$/, "") } : {},
|
|
31
34
|
...process.env.TCLOUD_API_URL ? { apiUrl: process.env.TCLOUD_API_URL.replace(/\/v1\/?$/, "") } : {},
|
|
32
|
-
...process.env.
|
|
33
|
-
...process.env.
|
|
35
|
+
...process.env.TCLOUD_API_KEY ? { apiKey: process.env.TCLOUD_API_KEY } : {},
|
|
36
|
+
...process.env.TANGLE_API_KEY ? { apiKey: process.env.TANGLE_API_KEY } : {}
|
|
34
37
|
};
|
|
35
38
|
}
|
|
36
39
|
function saveConfig(c) {
|
|
@@ -77,16 +80,6 @@ function teeType(value) {
|
|
|
77
80
|
if (!value) return void 0;
|
|
78
81
|
return value.toLowerCase();
|
|
79
82
|
}
|
|
80
|
-
function packageVersion() {
|
|
81
|
-
try {
|
|
82
|
-
const packageJson = JSON.parse(
|
|
83
|
-
fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
84
|
-
);
|
|
85
|
-
if (typeof packageJson.version === "string") return packageJson.version;
|
|
86
|
-
} catch {
|
|
87
|
-
}
|
|
88
|
-
return "0.0.0";
|
|
89
|
-
}
|
|
90
83
|
function printJson(value) {
|
|
91
84
|
console.log(JSON.stringify(value, null, 2));
|
|
92
85
|
}
|
|
@@ -386,6 +379,11 @@ program.command("search").description("Search the web").argument("<query>", "Sea
|
|
|
386
379
|
process.exit(1);
|
|
387
380
|
}
|
|
388
381
|
});
|
|
382
|
+
program.command("mcp").description('Run a Model Context Protocol (stdio) server exposing Tangle tools (web_search, deep_research). Mount with: { "command": ["tcloud", "mcp"] }').action(async () => {
|
|
383
|
+
const { runMcpServer } = await import("./mcp.js");
|
|
384
|
+
const client = getClient();
|
|
385
|
+
await runMcpServer(client);
|
|
386
|
+
});
|
|
389
387
|
program.command("image-generate").description("Generate an image").requiredOption("-p, --prompt <prompt>", "Prompt").option("-m, --model <model>", "Image model").option("--size <size>", "Output size").option("--quality <quality>", "Output quality").option("-n, --count <n>", "Number of images").option("--response-format <format>", "url or b64_json").option("--json", "Print raw JSON response").action(async (opts) => {
|
|
390
388
|
const client = getClient();
|
|
391
389
|
try {
|
|
@@ -186,6 +186,54 @@ interface SearchResponse {
|
|
|
186
186
|
billing_units?: Record<string, unknown>;
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
+
/** Providers served by the router's research API (POST /v1/research). Mirrors
|
|
190
|
+
* SearchProvider minus `brave` (no research API). Each has its own `effort`
|
|
191
|
+
* vocabulary — see ResearchOptions.effort. */
|
|
192
|
+
type ResearchProvider = 'perplexity' | 'exa' | 'you' | 'parallel' | 'tavily';
|
|
193
|
+
interface ResearchOptions {
|
|
194
|
+
query: string;
|
|
195
|
+
provider?: ResearchProvider;
|
|
196
|
+
/** Alias accepted by the Router for provider-compatible clients. */
|
|
197
|
+
model?: ResearchProvider;
|
|
198
|
+
/** Depth/cost dial, provider-specific:
|
|
199
|
+
* perplexity minimal|low|medium|high · you lite|standard|deep|exhaustive ·
|
|
200
|
+
* exa deep-lite|deep|deep-reasoning · tavily mini|pro|auto ·
|
|
201
|
+
* parallel lite|base|core|pro|ultra. Omit for the provider default. */
|
|
202
|
+
effort?: string;
|
|
203
|
+
maxResults?: number;
|
|
204
|
+
searchRecency?: SearchRecency;
|
|
205
|
+
includeDomains?: string[];
|
|
206
|
+
excludeDomains?: string[];
|
|
207
|
+
/** Optional JSON schema requesting structured output from the provider. */
|
|
208
|
+
outputSchema?: unknown;
|
|
209
|
+
}
|
|
210
|
+
interface ResearchHit {
|
|
211
|
+
title: string;
|
|
212
|
+
url: string;
|
|
213
|
+
snippet?: string;
|
|
214
|
+
publishedAt?: string;
|
|
215
|
+
source?: string;
|
|
216
|
+
}
|
|
217
|
+
interface ResearchResponse {
|
|
218
|
+
id: string;
|
|
219
|
+
object: 'research.result' | string;
|
|
220
|
+
provider: ResearchProvider;
|
|
221
|
+
query: string;
|
|
222
|
+
/** The synthesized multi-step research answer. */
|
|
223
|
+
answer: string;
|
|
224
|
+
/** Supporting sources behind the answer. */
|
|
225
|
+
results: ResearchHit[];
|
|
226
|
+
citations: string[];
|
|
227
|
+
/** Present when an outputSchema was requested and the provider honored it. */
|
|
228
|
+
structured?: unknown;
|
|
229
|
+
usage?: {
|
|
230
|
+
upstream_cost?: number;
|
|
231
|
+
billed_cost?: number;
|
|
232
|
+
gross_margin?: number;
|
|
233
|
+
markup?: number;
|
|
234
|
+
billing_units?: Record<string, unknown>;
|
|
235
|
+
};
|
|
236
|
+
}
|
|
189
237
|
interface WebSearchPlugin {
|
|
190
238
|
id: 'web';
|
|
191
239
|
engine?: 'native' | 'exa' | 'parallel' | 'firecrawl';
|
|
@@ -1039,6 +1087,11 @@ declare class TCloudClient {
|
|
|
1039
1087
|
rerank(options: RerankOptions): Promise<RerankResponse>;
|
|
1040
1088
|
/** Search the web through Tangle Router billing and provider routing. */
|
|
1041
1089
|
search(options: SearchOptions): Promise<SearchResponse>;
|
|
1090
|
+
/** Run a multi-step deep-research task through Tangle Router billing and
|
|
1091
|
+
* provider routing (POST /v1/research). Slower and costlier than `search` —
|
|
1092
|
+
* the provider synthesizes an answer over many fetches. Pick depth with
|
|
1093
|
+
* `effort` (provider-specific vocabulary; see {@link ResearchOptions.effort}). */
|
|
1094
|
+
research(options: ResearchOptions): Promise<ResearchResponse>;
|
|
1042
1095
|
/** Text-to-speech */
|
|
1043
1096
|
speech(options: {
|
|
1044
1097
|
model?: string;
|
|
@@ -1356,4 +1409,4 @@ declare class TCloudError extends Error {
|
|
|
1356
1409
|
constructor(status: number, message: string);
|
|
1357
1410
|
}
|
|
1358
1411
|
|
|
1359
|
-
export { type
|
|
1412
|
+
export { type SearchProvider as $, type ApiKeyInfo as A, type BatchJobResponse as B, type ChatCompletion as C, type RerankOptions as D, type EmbeddingOptions as E, type FineTuningJob as F, type GatewayOptions as G, type RerankResponse as H, type ImageEditAttachment as I, type JobEvent as J, type ResearchHit as K, type ResearchOptions as L, type Model as M, type ResearchProvider as N, type Operator as O, type PricingTier as P, type ResearchResponse as Q, type RotatingClientConfig as R, type RetryConfig as S, type TCloudConfig as T, type RotatingRoutingConfig as U, type RotationStats as V, type RoutingConfig as W, type RoutingStrategy as X, type SandboxChatOptions as Y, type SearchHit as Z, type SearchOptions as _, TCloudClient as a, type SearchRecency as a0, type SearchResponse as a1, type ShieldedConfig as a2, type SpendAuth as a3, type SpendingLimits as a4, TCloudError as a5, type TierConfig as a6, type TranscriptionResponse as a7, type UpdateKeyOptions as a8, type VideoGenerateOptions as a9, type VideoResponse as aa, type WatchJobOptions as ab, type WebSearchPlugin as ac, type AvatarGenerateRequest as b, type AvatarGenerateResponse as c, type AvatarJobStatus as d, type AvatarResult as e, type BatchRequest as f, type BridgeOptions as g, BridgeSession as h, type ChatCompletionChunk as i, type ChatMessage as j, type ChatOptions as k, type ChatPlugin as l, type CompletionOptions as m, type CompletionResponse as n, type CreateKeyOptions as o, type CreatedKey as p, type CreditBalance as q, type EmbeddingResponse as r, type FineTuningJobOptions as s, type ImageEditOptions as t, type ImageGenerateOptions as u, type ImageResponse as v, type OperatorInfo as w, type PrivacyConfig as x, PrivateRouter as y, type PrivateRouterConfig as z };
|