@ryuhq/sdk 0.1.14 → 0.2.2
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 +69 -7
- package/dist/action.cjs +839 -0
- package/dist/action.d.cts +88 -0
- package/dist/action.d.ts +88 -0
- package/dist/action.js +8 -0
- package/dist/agent-plugin.cjs +46 -0
- package/dist/agent-plugin.d.cts +43 -33
- package/dist/agent-plugin.d.ts +43 -33
- package/dist/agent-plugin.js +1 -1
- package/dist/agent.cjs +16 -0
- package/dist/agent.d.cts +377 -1
- package/dist/agent.d.ts +377 -1
- package/dist/agent.js +4 -2
- package/dist/app-B0Z9Ew_R.d.cts +141 -0
- package/dist/app-C-BDJwfG.d.ts +141 -0
- package/dist/builder.cjs +1194 -0
- package/dist/builder.d.cts +217 -0
- package/dist/builder.d.ts +217 -0
- package/dist/builder.js +29 -0
- package/dist/chunk-4TPUZDTI.js +94 -0
- package/dist/chunk-BC3A7HMO.js +164 -0
- package/dist/chunk-FZSFZOIN.js +200 -0
- package/dist/{chunk-ODFEUVPW.js → chunk-HACAGK65.js} +1 -18
- package/dist/chunk-HLKJZAFK.js +361 -0
- package/dist/chunk-IKEDLLFY.js +19 -0
- package/dist/{chunk-G6FLVEC4.js → chunk-JX6DDRXV.js} +46 -0
- package/dist/{chunk-AO2KJRDD.js → chunk-NZKVOSC2.js} +192 -3
- package/dist/chunk-QYFUNJOH.js +83 -0
- package/dist/chunk-SN2QBJUF.js +148 -0
- package/dist/chunk-TLDPEGC7.js +21 -0
- package/dist/chunk-TXSHHZF2.js +0 -0
- package/dist/chunk-VLIRNNAE.js +154 -0
- package/dist/{chunk-MTUBUPIV.js → chunk-Z57QDDJR.js} +8 -227
- package/dist/chunk-ZTJWBRUL.js +282 -0
- package/dist/cli.cjs +347 -18
- package/dist/cli.js +128 -23
- package/dist/client-D5U6ssPc.d.cts +84 -0
- package/dist/client-D5U6ssPc.d.ts +84 -0
- package/dist/index.cjs +810 -86
- package/dist/index.d.cts +19 -634
- package/dist/index.d.ts +19 -634
- package/dist/index.js +82 -699
- package/dist/manifest.cjs +200 -4
- package/dist/manifest.d.cts +260 -5
- package/dist/manifest.d.ts +260 -5
- package/dist/manifest.js +15 -1
- package/dist/mcp/client.cjs +180 -0
- package/dist/mcp/client.d.cts +49 -0
- package/dist/mcp/client.d.ts +49 -0
- package/dist/mcp/client.js +10 -0
- package/dist/mcp/server.cjs +370 -0
- package/dist/mcp/server.d.cts +127 -0
- package/dist/mcp/server.d.ts +127 -0
- package/dist/mcp/server.js +9 -0
- package/dist/mcp.cjs +376 -0
- package/dist/mcp.d.cts +2 -0
- package/dist/mcp.d.ts +2 -0
- package/dist/mcp.js +17 -0
- package/dist/model.cjs +141 -0
- package/dist/model.d.cts +33 -0
- package/dist/model.d.ts +33 -0
- package/dist/model.js +18 -0
- package/dist/plugin.cjs +46 -0
- package/dist/plugin.d.cts +215 -0
- package/dist/plugin.d.ts +215 -0
- package/dist/plugin.js +8 -0
- package/dist/runnable.cjs +1438 -0
- package/dist/runnable.d.cts +274 -0
- package/dist/runnable.d.ts +274 -0
- package/dist/runnable.js +34 -0
- package/dist/{index-B6SkaAjJ.d.ts → tool-AjkdFvhE.d.ts} +88 -461
- package/dist/{index-BvAB5eMk.d.cts → tool-CgzW92O_.d.cts} +88 -461
- package/package.json +48 -3
- package/src/agent/loop.test.ts +4 -4
- package/src/agent/tools.ts +3 -3
- package/src/agent-plugin.test.ts +58 -0
- package/src/agent-plugin.ts +109 -36
- package/src/builder.ts +9 -0
- package/src/cli/dev.test.ts +26 -47
- package/src/cli/dev.ts +10 -2
- package/src/cli-security.test.ts +109 -0
- package/src/cli.ts +141 -25
- package/src/contracts-lockstep.test.ts +16 -2
- package/src/exports-lockstep.test.ts +93 -0
- package/src/generated/plugin-manifest.ts +322 -29
- package/src/index.ts +53 -0
- package/src/manifest-schema.test.ts +30 -1
- package/src/manifest.fixtures.test.ts +22 -6
- package/src/manifest.test.ts +165 -10
- package/src/manifest.ts +454 -188
- package/src/mcp/index.ts +18 -0
- package/src/mcp/server.ts +2 -1
- package/src/model/index.ts +22 -0
- package/src/plugin/ryu-plugin.ts +82 -0
- package/src/runnable/action.test.ts +128 -0
- package/src/runnable/action.ts +202 -0
- package/src/runnable/app.test.ts +2 -0
- package/src/runnable/app.ts +50 -14
- package/src/runnable/index.ts +20 -3
- package/src/runnable/primitives.test.ts +34 -0
- package/src/runnable/primitives.ts +116 -0
- package/src/runnable/runnable-types.ts +3 -0
- package/src/runnable/tool.ts +36 -5
- package/src/runnable/turn-hook.ts +8 -3
- package/src/slash-command.test.ts +69 -0
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import {
|
|
3
|
-
PluginManifestSchema
|
|
4
|
-
} from "./chunk-AO2KJRDD.js";
|
|
5
2
|
import {
|
|
6
3
|
AGENT_PLUGIN_MANIFEST_FILE,
|
|
7
4
|
AGENT_PLUGIN_MCP_FILE,
|
|
8
5
|
isAgentPluginManifest,
|
|
9
6
|
toAgentPlugin
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-JX6DDRXV.js";
|
|
8
|
+
import {
|
|
9
|
+
PluginManifestSchema
|
|
10
|
+
} from "./chunk-NZKVOSC2.js";
|
|
11
|
+
import {
|
|
12
|
+
ModelClient
|
|
13
|
+
} from "./chunk-HACAGK65.js";
|
|
11
14
|
import {
|
|
12
|
-
ModelClient,
|
|
13
15
|
resolveGatewayUrl
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-IKEDLLFY.js";
|
|
15
17
|
|
|
16
18
|
// src/cli.ts
|
|
17
19
|
import { createHash } from "crypto";
|
|
@@ -19,17 +21,19 @@ import {
|
|
|
19
21
|
existsSync,
|
|
20
22
|
mkdirSync,
|
|
21
23
|
readFileSync,
|
|
24
|
+
realpathSync,
|
|
22
25
|
rmSync,
|
|
23
|
-
writeFileSync
|
|
26
|
+
writeFileSync,
|
|
27
|
+
writeSync
|
|
24
28
|
} from "fs";
|
|
25
|
-
import { join, resolve } from "path";
|
|
29
|
+
import { isAbsolute, join, relative, resolve, sep } from "path";
|
|
26
30
|
|
|
27
31
|
// src/cli/dev.ts
|
|
28
32
|
import { createInterface } from "readline";
|
|
29
33
|
var RE_ABSOLUTE_PATH = /^[A-Za-z]:[\\/]/;
|
|
30
|
-
async function probeGateway(baseUrl) {
|
|
34
|
+
async function probeGateway(baseUrl, fetchImpl = fetch) {
|
|
31
35
|
try {
|
|
32
|
-
await
|
|
36
|
+
await fetchImpl(`${baseUrl}/health`, {
|
|
33
37
|
method: "HEAD",
|
|
34
38
|
signal: AbortSignal.timeout(3e3)
|
|
35
39
|
});
|
|
@@ -228,7 +232,9 @@ function printUsage() {
|
|
|
228
232
|
"",
|
|
229
233
|
"Usage:",
|
|
230
234
|
" bunx ryu pack <dir> Validate and bundle a manifest.json Plugin",
|
|
231
|
-
" bunx ryu publish <
|
|
235
|
+
" bunx ryu github-publish <url>",
|
|
236
|
+
" Submit a GitHub repository/package URL to the Marketplace",
|
|
237
|
+
" bunx ryu publish <dir> Deprecated server-artifact publishing (migration only)",
|
|
232
238
|
" bunx ryu dev <entry> Run a Runnable locally with an interactive chat loop",
|
|
233
239
|
" bunx ryu agent-plugin <dir>",
|
|
234
240
|
" Emit the Agent Plugins v1 interop pair (plugin.json + mcp.json)",
|
|
@@ -237,7 +243,7 @@ function printUsage() {
|
|
|
237
243
|
);
|
|
238
244
|
}
|
|
239
245
|
function exitError(message) {
|
|
240
|
-
process.stderr.
|
|
246
|
+
writeSync(process.stderr.fd, `error: ${message}
|
|
241
247
|
`);
|
|
242
248
|
process.exit(1);
|
|
243
249
|
}
|
|
@@ -247,16 +253,20 @@ var MANIFEST_FILE_NAMES = [
|
|
|
247
253
|
"ryu.json"
|
|
248
254
|
];
|
|
249
255
|
function resolveNativeManifestPath(dir) {
|
|
250
|
-
return MANIFEST_FILE_NAMES.map((name) => join(dir, name)).find(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
256
|
+
return MANIFEST_FILE_NAMES.map((name) => join(dir, name)).find(
|
|
257
|
+
(candidate) => {
|
|
258
|
+
if (!existsSync(candidate)) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
return !isAgentPluginManifest(
|
|
263
|
+
JSON.parse(readFileSync(candidate, "utf8"))
|
|
264
|
+
);
|
|
265
|
+
} catch {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
258
268
|
}
|
|
259
|
-
|
|
269
|
+
);
|
|
260
270
|
}
|
|
261
271
|
function loadManifest(dir) {
|
|
262
272
|
const manifestPath = resolveNativeManifestPath(dir);
|
|
@@ -286,13 +296,30 @@ function loadManifest(dir) {
|
|
|
286
296
|
}
|
|
287
297
|
var CODE_FILE_DIRS = ["hooks", "adapters"];
|
|
288
298
|
var CODE_FILE_PATH = /^(hooks|adapters)\/[A-Za-z0-9_][A-Za-z0-9._-]*\.m?js$/;
|
|
299
|
+
function containedPackageFile(dir, rel, label) {
|
|
300
|
+
let realRoot;
|
|
301
|
+
let realTarget;
|
|
302
|
+
try {
|
|
303
|
+
realRoot = realpathSync(dir);
|
|
304
|
+
realTarget = realpathSync(join(dir, rel));
|
|
305
|
+
} catch (error) {
|
|
306
|
+
exitError(`${label}: could not resolve '${rel}': ${String(error)}`);
|
|
307
|
+
}
|
|
308
|
+
const fromRoot = relative(realRoot, realTarget);
|
|
309
|
+
if (fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
|
|
310
|
+
exitError(
|
|
311
|
+
`${label}: '${rel}' resolves outside the plugin package (${realTarget})`
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
return realTarget;
|
|
315
|
+
}
|
|
289
316
|
function readCodeFile(dir, rel, label) {
|
|
290
317
|
if (!CODE_FILE_PATH.test(rel)) {
|
|
291
318
|
exitError(
|
|
292
319
|
`${label}: code_file '${rel}' must be exactly '<${CODE_FILE_DIRS.join("|")}>/<name>.js' with no traversal`
|
|
293
320
|
);
|
|
294
321
|
}
|
|
295
|
-
const path =
|
|
322
|
+
const path = containedPackageFile(dir, rel, label);
|
|
296
323
|
let body;
|
|
297
324
|
try {
|
|
298
325
|
body = readFileSync(path, "utf8");
|
|
@@ -342,7 +369,7 @@ function inlineOutputStyleFiles(manifest, dir) {
|
|
|
342
369
|
}
|
|
343
370
|
let body;
|
|
344
371
|
try {
|
|
345
|
-
body = readFileSync(
|
|
372
|
+
body = readFileSync(containedPackageFile(dir, rel, label), "utf8");
|
|
346
373
|
} catch (err) {
|
|
347
374
|
exitError(`${label}: could not read file '${rel}': ${String(err)}`);
|
|
348
375
|
}
|
|
@@ -388,6 +415,12 @@ function resolveUiFormat(manifest) {
|
|
|
388
415
|
return "html";
|
|
389
416
|
}
|
|
390
417
|
}
|
|
418
|
+
for (const widget of manifest.contributes?.widgets ?? []) {
|
|
419
|
+
const entry = widget.ui_entry;
|
|
420
|
+
if (typeof entry === "string" && entry.trim().toLowerCase().endsWith(".html")) {
|
|
421
|
+
return "html";
|
|
422
|
+
}
|
|
423
|
+
}
|
|
391
424
|
return "js";
|
|
392
425
|
}
|
|
393
426
|
function readUiEntryHtml(dir, uiEntry) {
|
|
@@ -519,8 +552,16 @@ async function commandPublish(rawDir) {
|
|
|
519
552
|
...manifest.description ? { description: manifest.description } : {},
|
|
520
553
|
...manifest.tagline ? { tagline: manifest.tagline } : {},
|
|
521
554
|
...developer ? { developer } : {},
|
|
555
|
+
...manifest.author ? { author: manifest.author } : {},
|
|
556
|
+
...manifest.repository ? { repository: manifest.repository } : {},
|
|
557
|
+
...manifest.external ? { external: true } : {},
|
|
522
558
|
...manifest.category ? { category: manifest.category } : {},
|
|
559
|
+
...manifest.license ? { license: manifest.license } : {},
|
|
560
|
+
...manifest.keywords?.length ? { keywords: manifest.keywords } : {},
|
|
523
561
|
...manifest.iconUrl ? { iconUrl: manifest.iconUrl } : {},
|
|
562
|
+
...manifest.icon ? { icon: manifest.icon } : {},
|
|
563
|
+
...manifest.iconDither ? { iconDither: manifest.iconDither } : {},
|
|
564
|
+
...manifest.banner ? { banner: manifest.banner } : {},
|
|
524
565
|
...manifest.screenshots?.length ? { screenshots: manifest.screenshots } : {},
|
|
525
566
|
...manifest.homepage ? { website: manifest.homepage } : {},
|
|
526
567
|
...manifest.privacyPolicyUrl ? { privacyPolicyUrl: manifest.privacyPolicyUrl } : {},
|
|
@@ -576,6 +617,55 @@ ${text}
|
|
|
576
617
|
`
|
|
577
618
|
);
|
|
578
619
|
}
|
|
620
|
+
async function commandGithubPublish(repositoryUrl) {
|
|
621
|
+
const input = repositoryUrl.trim();
|
|
622
|
+
if (!input) {
|
|
623
|
+
exitError(
|
|
624
|
+
"github-publish requires a GitHub repository or package URL, for example https://github.com/acme/my-app"
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
const token = authToken();
|
|
628
|
+
const url = `${publishBaseUrl()}/api/marketplace/github/publish`;
|
|
629
|
+
const proof = process.env.RYU_GITHUB_INSTALLATION_PROOF?.trim();
|
|
630
|
+
const body = {
|
|
631
|
+
url: input,
|
|
632
|
+
...proof ? { installationProof: proof } : {}
|
|
633
|
+
};
|
|
634
|
+
let response;
|
|
635
|
+
try {
|
|
636
|
+
response = await fetch(url, {
|
|
637
|
+
method: "POST",
|
|
638
|
+
headers: {
|
|
639
|
+
authorization: `Bearer ${token}`,
|
|
640
|
+
"content-type": "application/json"
|
|
641
|
+
},
|
|
642
|
+
body: JSON.stringify(body)
|
|
643
|
+
});
|
|
644
|
+
} catch (error) {
|
|
645
|
+
exitError(`could not reach ${url}: ${String(error)}`);
|
|
646
|
+
}
|
|
647
|
+
const text = await response.text();
|
|
648
|
+
if (!response.ok) {
|
|
649
|
+
try {
|
|
650
|
+
const error = JSON.parse(text);
|
|
651
|
+
if (error.installationUrl) {
|
|
652
|
+
exitError(
|
|
653
|
+
`${error.error ?? "GitHub App installation required"}. Open ${error.installationUrl}, then set RYU_GITHUB_INSTALLATION_PROOF to the callback proof and retry.`
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
exitError(
|
|
657
|
+
`github-publish failed (${response.status}): ${error.error ?? text}`
|
|
658
|
+
);
|
|
659
|
+
} catch {
|
|
660
|
+
exitError(`github-publish failed (${response.status}): ${text}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
process.stdout.write(
|
|
664
|
+
`GitHub-backed listing submitted for moderation:
|
|
665
|
+
${text}
|
|
666
|
+
`
|
|
667
|
+
);
|
|
668
|
+
}
|
|
579
669
|
var [, , command, ...args] = process.argv;
|
|
580
670
|
if (!command) {
|
|
581
671
|
printUsage();
|
|
@@ -594,9 +684,24 @@ if (command === "pack") {
|
|
|
594
684
|
if (!dir) {
|
|
595
685
|
exitError("publish requires a directory argument: bunx ryu publish <dir>");
|
|
596
686
|
}
|
|
687
|
+
if (process.env.RYU_ENABLE_LEGACY_MARKETPLACE_WRITES !== "true") {
|
|
688
|
+
exitError(
|
|
689
|
+
"ryu publish is deprecated because marketplace package contents now live in GitHub Releases; use bunx ryu github-publish <repository-or-package-url>"
|
|
690
|
+
);
|
|
691
|
+
}
|
|
597
692
|
commandPublish(dir).catch((err) => {
|
|
598
693
|
exitError(String(err));
|
|
599
694
|
});
|
|
695
|
+
} else if (command === "github-publish") {
|
|
696
|
+
const repositoryUrl = args[0];
|
|
697
|
+
if (!repositoryUrl) {
|
|
698
|
+
exitError(
|
|
699
|
+
"github-publish requires a GitHub repository or package URL, for example https://github.com/acme/my-app"
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
commandGithubPublish(repositoryUrl).catch((err) => {
|
|
703
|
+
exitError(String(err));
|
|
704
|
+
});
|
|
600
705
|
} else if (command === "agent-plugin") {
|
|
601
706
|
const dir = args[0];
|
|
602
707
|
if (!dir) {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway-mandatory model client for the Ryu SDK.
|
|
3
|
+
*
|
|
4
|
+
* Rust-cored: this is a thin TypeScript wrapper over the `@ryuhq/sdk-native`
|
|
5
|
+
* addon's `ModelClient`, which is the `crates/ryu-sdk` Rust core. Every model
|
|
6
|
+
* call is routed by the Rust core to the Ryu gateway's OpenAI-compatible
|
|
7
|
+
* `/v1/chat/completions` endpoint; direct-provider base URLs are rejected at
|
|
8
|
+
* construction. No provider SDK or base URL is ever imported here.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
*
|
|
12
|
+
* const model = defineModel("gpt-4o");
|
|
13
|
+
* const reply = await model.chat([{ role: "user", content: "hello" }]);
|
|
14
|
+
* for await (const delta of model.stream([{ role: "user", content: "hi" }])) {
|
|
15
|
+
* process.stdout.write(delta.content);
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
/** A single message in a chat conversation. */
|
|
19
|
+
interface ChatMessage {
|
|
20
|
+
/** The message text. */
|
|
21
|
+
content: string;
|
|
22
|
+
/** The speaker: "system", "user", or "assistant". */
|
|
23
|
+
role: "system" | "user" | "assistant";
|
|
24
|
+
}
|
|
25
|
+
/** A streaming chat completion delta. */
|
|
26
|
+
interface ChatDelta {
|
|
27
|
+
/** Incremental text fragment from the model. */
|
|
28
|
+
content: string | null;
|
|
29
|
+
/** Non-null on the final chunk when `finish_reason` is set. */
|
|
30
|
+
finishReason: string | null;
|
|
31
|
+
}
|
|
32
|
+
/** Non-streaming chat completion result. */
|
|
33
|
+
interface ChatResult {
|
|
34
|
+
/** The full assistant reply text. */
|
|
35
|
+
content: string;
|
|
36
|
+
/** The gateway/model-reported finish reason. */
|
|
37
|
+
finishReason: string | null;
|
|
38
|
+
/** Usage stats as reported by the gateway (optional — gateway may omit). */
|
|
39
|
+
usage?: {
|
|
40
|
+
promptTokens: number;
|
|
41
|
+
completionTokens: number;
|
|
42
|
+
totalTokens: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Options accepted by `defineModel`. */
|
|
46
|
+
interface ModelClientOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Gateway base URL (no trailing `/v1`). Defaults to `RYU_GATEWAY_URL` then
|
|
49
|
+
* the Rust core's default. Direct provider URLs are rejected at construction.
|
|
50
|
+
*/
|
|
51
|
+
baseUrl?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Bearer token forwarded to the gateway. Defaults to `RYU_GATEWAY_TOKEN`.
|
|
54
|
+
* This is the gateway token, never a provider API key.
|
|
55
|
+
*/
|
|
56
|
+
token?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A gateway-mandatory model client backed by the Rust core.
|
|
60
|
+
*
|
|
61
|
+
* All calls go through the native `ModelClient`; if the configured base URL is a
|
|
62
|
+
* direct provider, construction throws.
|
|
63
|
+
*/
|
|
64
|
+
declare class ModelClient {
|
|
65
|
+
readonly model: string;
|
|
66
|
+
readonly baseUrl: string;
|
|
67
|
+
private readonly native;
|
|
68
|
+
constructor(model: string, options?: ModelClientOptions);
|
|
69
|
+
/** Send a non-streaming chat completion request to the gateway. */
|
|
70
|
+
chat(messages: ChatMessage[]): Promise<ChatResult>;
|
|
71
|
+
/** Send a streaming chat completion request, yielding deltas as they arrive. */
|
|
72
|
+
stream(messages: ChatMessage[]): AsyncGenerator<ChatDelta>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create a gateway-mandatory model client for `modelId`.
|
|
76
|
+
*
|
|
77
|
+
* const model = defineModel("gpt-4o");
|
|
78
|
+
* const model = defineModel("claude-3-5-sonnet", { baseUrl: "http://my-gateway:7981" });
|
|
79
|
+
*
|
|
80
|
+
* A direct provider URL throws immediately (egress enforcement in the Rust core).
|
|
81
|
+
*/
|
|
82
|
+
declare function defineModel(modelId: string, options?: ModelClientOptions): ModelClient;
|
|
83
|
+
|
|
84
|
+
export { type ChatDelta as C, ModelClient as M, type ChatMessage as a, type ChatResult as b, type ModelClientOptions as c, defineModel as d };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway-mandatory model client for the Ryu SDK.
|
|
3
|
+
*
|
|
4
|
+
* Rust-cored: this is a thin TypeScript wrapper over the `@ryuhq/sdk-native`
|
|
5
|
+
* addon's `ModelClient`, which is the `crates/ryu-sdk` Rust core. Every model
|
|
6
|
+
* call is routed by the Rust core to the Ryu gateway's OpenAI-compatible
|
|
7
|
+
* `/v1/chat/completions` endpoint; direct-provider base URLs are rejected at
|
|
8
|
+
* construction. No provider SDK or base URL is ever imported here.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
*
|
|
12
|
+
* const model = defineModel("gpt-4o");
|
|
13
|
+
* const reply = await model.chat([{ role: "user", content: "hello" }]);
|
|
14
|
+
* for await (const delta of model.stream([{ role: "user", content: "hi" }])) {
|
|
15
|
+
* process.stdout.write(delta.content);
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
/** A single message in a chat conversation. */
|
|
19
|
+
interface ChatMessage {
|
|
20
|
+
/** The message text. */
|
|
21
|
+
content: string;
|
|
22
|
+
/** The speaker: "system", "user", or "assistant". */
|
|
23
|
+
role: "system" | "user" | "assistant";
|
|
24
|
+
}
|
|
25
|
+
/** A streaming chat completion delta. */
|
|
26
|
+
interface ChatDelta {
|
|
27
|
+
/** Incremental text fragment from the model. */
|
|
28
|
+
content: string | null;
|
|
29
|
+
/** Non-null on the final chunk when `finish_reason` is set. */
|
|
30
|
+
finishReason: string | null;
|
|
31
|
+
}
|
|
32
|
+
/** Non-streaming chat completion result. */
|
|
33
|
+
interface ChatResult {
|
|
34
|
+
/** The full assistant reply text. */
|
|
35
|
+
content: string;
|
|
36
|
+
/** The gateway/model-reported finish reason. */
|
|
37
|
+
finishReason: string | null;
|
|
38
|
+
/** Usage stats as reported by the gateway (optional — gateway may omit). */
|
|
39
|
+
usage?: {
|
|
40
|
+
promptTokens: number;
|
|
41
|
+
completionTokens: number;
|
|
42
|
+
totalTokens: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Options accepted by `defineModel`. */
|
|
46
|
+
interface ModelClientOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Gateway base URL (no trailing `/v1`). Defaults to `RYU_GATEWAY_URL` then
|
|
49
|
+
* the Rust core's default. Direct provider URLs are rejected at construction.
|
|
50
|
+
*/
|
|
51
|
+
baseUrl?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Bearer token forwarded to the gateway. Defaults to `RYU_GATEWAY_TOKEN`.
|
|
54
|
+
* This is the gateway token, never a provider API key.
|
|
55
|
+
*/
|
|
56
|
+
token?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A gateway-mandatory model client backed by the Rust core.
|
|
60
|
+
*
|
|
61
|
+
* All calls go through the native `ModelClient`; if the configured base URL is a
|
|
62
|
+
* direct provider, construction throws.
|
|
63
|
+
*/
|
|
64
|
+
declare class ModelClient {
|
|
65
|
+
readonly model: string;
|
|
66
|
+
readonly baseUrl: string;
|
|
67
|
+
private readonly native;
|
|
68
|
+
constructor(model: string, options?: ModelClientOptions);
|
|
69
|
+
/** Send a non-streaming chat completion request to the gateway. */
|
|
70
|
+
chat(messages: ChatMessage[]): Promise<ChatResult>;
|
|
71
|
+
/** Send a streaming chat completion request, yielding deltas as they arrive. */
|
|
72
|
+
stream(messages: ChatMessage[]): AsyncGenerator<ChatDelta>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create a gateway-mandatory model client for `modelId`.
|
|
76
|
+
*
|
|
77
|
+
* const model = defineModel("gpt-4o");
|
|
78
|
+
* const model = defineModel("claude-3-5-sonnet", { baseUrl: "http://my-gateway:7981" });
|
|
79
|
+
*
|
|
80
|
+
* A direct provider URL throws immediately (egress enforcement in the Rust core).
|
|
81
|
+
*/
|
|
82
|
+
declare function defineModel(modelId: string, options?: ModelClientOptions): ModelClient;
|
|
83
|
+
|
|
84
|
+
export { type ChatDelta as C, ModelClient as M, type ChatMessage as a, type ChatResult as b, type ModelClientOptions as c, defineModel as d };
|