@ryuhq/sdk 0.2.0 → 0.2.3
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 +51 -2
- 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.d.cts +1 -1
- package/dist/agent-plugin.d.ts +1 -1
- package/dist/agent.cjs +7 -0
- package/dist/agent.d.cts +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{app-DNaGmLVf.d.cts → app-B0Z9Ew_R.d.cts} +18 -6
- package/dist/{app-Bkw7LlCK.d.ts → app-C-BDJwfG.d.ts} +18 -6
- package/dist/builder.cjs +110 -11
- package/dist/builder.d.cts +7 -2
- package/dist/builder.d.ts +7 -2
- package/dist/builder.js +4 -3
- package/dist/chunk-4TPUZDTI.js +94 -0
- package/dist/{chunk-T5676WL2.js → chunk-BC3A7HMO.js} +1 -77
- package/dist/{chunk-IOLP5FFE.js → chunk-HLKJZAFK.js} +9 -2
- package/dist/{chunk-IEUQ3CDG.js → chunk-NZKVOSC2.js} +71 -5
- package/dist/chunk-QYFUNJOH.js +83 -0
- package/dist/{chunk-W3KPP4WN.js → chunk-SN2QBJUF.js} +20 -7
- package/dist/{chunk-ULSVL7EC.js → chunk-Z57QDDJR.js} +1 -1
- package/dist/{chunk-A3RGEPDG.js → chunk-ZTJWBRUL.js} +32 -0
- package/dist/cli.cjs +93 -8
- package/dist/cli.js +33 -8
- package/dist/index.cjs +297 -87
- package/dist/index.d.cts +10 -9
- package/dist/index.d.ts +10 -9
- package/dist/index.js +34 -19
- package/dist/manifest.cjs +76 -6
- package/dist/manifest.d.cts +157 -5
- package/dist/manifest.d.ts +157 -5
- package/dist/manifest.js +9 -1
- package/dist/mcp/server.d.cts +2 -1
- package/dist/mcp/server.d.ts +2 -1
- package/dist/runnable.cjs +279 -71
- package/dist/runnable.d.cts +6 -3
- package/dist/runnable.d.ts +6 -3
- package/dist/runnable.js +11 -5
- package/dist/{tool-DSx2bFx8.d.ts → tool-AjkdFvhE.d.ts} +54 -4
- package/dist/{tool-u-VR0fLF.d.cts → tool-CgzW92O_.d.cts} +54 -4
- package/package.json +11 -2
- package/src/agent-plugin.ts +1 -1
- package/src/builder.ts +9 -0
- package/src/cli-security.test.ts +109 -0
- package/src/cli.ts +43 -10
- package/src/contracts-lockstep.test.ts +16 -2
- package/src/exports-lockstep.test.ts +1 -0
- package/src/generated/plugin-manifest.ts +82 -5
- package/src/index.ts +18 -0
- package/src/manifest-schema.test.ts +1 -1
- package/src/manifest.fixtures.test.ts +9 -3
- package/src/manifest.test.ts +69 -0
- package/src/manifest.ts +137 -18
- package/src/mcp/server.ts +2 -1
- package/src/runnable/action.test.ts +128 -0
- package/src/runnable/action.ts +202 -0
- package/src/runnable/app.ts +45 -12
- package/src/runnable/index.ts +18 -3
- package/src/runnable/primitives.test.ts +34 -0
- package/src/runnable/primitives.ts +59 -0
- package/src/runnable/runnable-types.ts +3 -0
- package/src/runnable/tool.ts +35 -4
- package/src/runnable/turn-hook.ts +4 -2
- package/src/slash-command.test.ts +69 -0
package/dist/runnable.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(runnable_exports, {
|
|
|
33
33
|
PRIMITIVE_BINDINGS: () => PRIMITIVE_BINDINGS,
|
|
34
34
|
appToolId: () => appToolId,
|
|
35
35
|
createPrimitives: () => createPrimitives,
|
|
36
|
+
defineAction: () => defineAction,
|
|
36
37
|
defineAgent: () => defineAgent,
|
|
37
38
|
defineApp: () => defineApp,
|
|
38
39
|
defineSkill: () => defineSkill,
|
|
@@ -185,10 +186,18 @@ var ChatWidgetTemplateSchema = import_zod.z.object({
|
|
|
185
186
|
}).superRefine((value, ctx) => {
|
|
186
187
|
const count = Number(Boolean(value.backing.tool_id)) + Number(Boolean(value.backing.view_id));
|
|
187
188
|
if (count !== 1 && value.availability === "available") {
|
|
188
|
-
ctx.addIssue({
|
|
189
|
+
ctx.addIssue({
|
|
190
|
+
code: "custom",
|
|
191
|
+
path: ["backing"],
|
|
192
|
+
message: "available templates need exactly one backing tool_id or view_id"
|
|
193
|
+
});
|
|
189
194
|
}
|
|
190
195
|
if (count > 1) {
|
|
191
|
-
ctx.addIssue({
|
|
196
|
+
ctx.addIssue({
|
|
197
|
+
code: "custom",
|
|
198
|
+
path: ["backing"],
|
|
199
|
+
message: "backing must declare at most one of tool_id or view_id"
|
|
200
|
+
});
|
|
192
201
|
}
|
|
193
202
|
});
|
|
194
203
|
var ToolAppConfigSchema = import_zod.z.object({
|
|
@@ -211,6 +220,33 @@ var ToolAppConfigSchema = import_zod.z.object({
|
|
|
211
220
|
/** Optional status label shown when the render tool finishes. */
|
|
212
221
|
invoked: import_zod.z.string().optional()
|
|
213
222
|
});
|
|
223
|
+
var SlashCommandOptionSchema = import_zod.z.object({
|
|
224
|
+
description: import_zod.z.string().optional(),
|
|
225
|
+
label: import_zod.z.string().min(1),
|
|
226
|
+
value: import_zod.z.string().min(1)
|
|
227
|
+
}).passthrough();
|
|
228
|
+
var SlashCommandCustomOptionSchema = import_zod.z.union([
|
|
229
|
+
import_zod.z.literal(true),
|
|
230
|
+
import_zod.z.object({
|
|
231
|
+
description: import_zod.z.string().optional(),
|
|
232
|
+
label: import_zod.z.string().min(1).optional()
|
|
233
|
+
}).passthrough()
|
|
234
|
+
]);
|
|
235
|
+
var SlashCommandArgumentSchema = import_zod.z.object({
|
|
236
|
+
allow_custom: import_zod.z.boolean().optional(),
|
|
237
|
+
custom: SlashCommandCustomOptionSchema.optional(),
|
|
238
|
+
description: import_zod.z.string().optional(),
|
|
239
|
+
name: import_zod.z.string().min(1),
|
|
240
|
+
options: import_zod.z.array(SlashCommandOptionSchema).optional()
|
|
241
|
+
}).passthrough();
|
|
242
|
+
var SlashCommandContributionSchema = import_zod.z.object({
|
|
243
|
+
args: import_zod.z.array(SlashCommandArgumentSchema).optional(),
|
|
244
|
+
body: import_zod.z.string().optional(),
|
|
245
|
+
command: import_zod.z.string().min(1),
|
|
246
|
+
description: import_zod.z.string().optional(),
|
|
247
|
+
id: import_zod.z.string().optional(),
|
|
248
|
+
parameters: import_zod.z.array(SlashCommandArgumentSchema).optional()
|
|
249
|
+
}).passthrough();
|
|
214
250
|
var ContributesSchema = import_zod.z.object({
|
|
215
251
|
turn_hooks: import_zod.z.array(TurnHookContributionSchema).default([]),
|
|
216
252
|
/** App events this plugin EMITS — the provider half of the hook system, whose
|
|
@@ -225,7 +261,7 @@ var ContributesSchema = import_zod.z.object({
|
|
|
225
261
|
* feature declaration before signing. */
|
|
226
262
|
chat_features: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
227
263
|
settings_tabs: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
228
|
-
slash_commands: import_zod.z.array(
|
|
264
|
+
slash_commands: import_zod.z.array(SlashCommandContributionSchema).default([]),
|
|
229
265
|
/** App widgets (Ryu Apps). Each binds a render tool id to its
|
|
230
266
|
* `ui://widget/<slug>.html` template. Mirrors the Rust-side
|
|
231
267
|
* `Contributes.widgets` field, without which the CLI's zod parse would strip
|
|
@@ -292,7 +328,10 @@ var ContributesSchema = import_zod.z.object({
|
|
|
292
328
|
output_styles: import_zod.z.array(OutputStyleContributionSchema).default([]),
|
|
293
329
|
/** Per-message actions contributed by an enabled plugin. Kept as loose records
|
|
294
330
|
* so renderer-specific `kind`/`args` payloads survive `ryu pack` unchanged. */
|
|
295
|
-
message_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([])
|
|
331
|
+
message_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
332
|
+
/** Buttons contributed to the floating text-selection toolbar. Kept as loose
|
|
333
|
+
* records so host-owned dispatch args survive `ryu pack` unchanged. */
|
|
334
|
+
selection_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([])
|
|
296
335
|
});
|
|
297
336
|
var SetupStepSchema = import_zod.z.object({
|
|
298
337
|
/** Card heading (e.g. the companion app name). */
|
|
@@ -442,6 +481,9 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
442
481
|
/^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/,
|
|
443
482
|
"version must be a valid semver string (e.g. 1.0.0)"
|
|
444
483
|
),
|
|
484
|
+
/** Core-owned release maturity metadata. The Rust contract validates the
|
|
485
|
+
* richer shape; the SDK authoring parser must preserve it for pack/publish. */
|
|
486
|
+
stability: import_zod.z.unknown().optional(),
|
|
445
487
|
/**
|
|
446
488
|
* Lower-case hex `sha256(utf8_bytes(ui_code))` binding the plugin's bundled
|
|
447
489
|
* sandboxed-UI code to this manifest. `ryu pack` / `ryu publish` compute it and
|
|
@@ -459,8 +501,26 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
459
501
|
* Declarations only — grant enforcement is the Gateway's responsibility.
|
|
460
502
|
*/
|
|
461
503
|
permission_grants: import_zod.z.array(import_zod.z.string()).default([]),
|
|
504
|
+
/** Deny-by-default sandbox permissions. Core remains authoritative; this
|
|
505
|
+
* schema mirrors the fields so `ryu pack` cannot strip them. */
|
|
506
|
+
permissions: import_zod.z.object({
|
|
507
|
+
fs: import_zod.z.object({
|
|
508
|
+
read: import_zod.z.array(import_zod.z.string()).default([]),
|
|
509
|
+
write: import_zod.z.array(import_zod.z.string()).default([])
|
|
510
|
+
}).optional(),
|
|
511
|
+
child_process: import_zod.z.boolean().optional(),
|
|
512
|
+
run: import_zod.z.array(import_zod.z.string()).default([]),
|
|
513
|
+
network: import_zod.z.union([import_zod.z.boolean(), import_zod.z.array(import_zod.z.string())]).optional(),
|
|
514
|
+
tool: import_zod.z.array(import_zod.z.string()).default([])
|
|
515
|
+
}).optional(),
|
|
516
|
+
/** Core-owned permission presentation levels. Preserved verbatim here and
|
|
517
|
+
* validated by Core's authoritative manifest contract. */
|
|
518
|
+
permission_levels: import_zod.z.unknown().optional(),
|
|
462
519
|
/** Remote or stdio MCP servers registered by this plugin. */
|
|
463
520
|
mcp_servers: import_zod.z.record(import_zod.z.string(), McpServerDeclSchema).optional(),
|
|
521
|
+
/** Core-owned sidecar declarations. Their full process/HTTP schema stays in
|
|
522
|
+
* the Rust contract; this authoring layer must never strip them. */
|
|
523
|
+
sidecars: import_zod.z.unknown().optional(),
|
|
464
524
|
/**
|
|
465
525
|
* Optional Companion surface (an in-desktop overlay or sidebar panel).
|
|
466
526
|
* Absent when the plugin has no Companion surface.
|
|
@@ -496,6 +556,9 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
496
556
|
* an unsupported-target plugin stays installable and inspectable.
|
|
497
557
|
*/
|
|
498
558
|
targets: import_zod.z.array(SurfaceSchema).default([]),
|
|
559
|
+
/** Rich per-surface declarations (`support`, UI, contributed commands, …).
|
|
560
|
+
* Core owns and validates the nested vocabulary. */
|
|
561
|
+
surfaces: import_zod.z.unknown().optional(),
|
|
499
562
|
/**
|
|
500
563
|
* Host version floors — the semver requirement each surface must satisfy for
|
|
501
564
|
* this plugin to install. Mirrors Core's `EnginesReq`
|
|
@@ -610,7 +673,7 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
610
673
|
* array of steps guiding the user through post-install configuration.
|
|
611
674
|
*/
|
|
612
675
|
setup: import_zod.z.union([SetupStepSchema, import_zod.z.array(SetupStepSchema)]).optional()
|
|
613
|
-
}).superRefine((manifest, context) => {
|
|
676
|
+
}).passthrough().superRefine((manifest, context) => {
|
|
614
677
|
const hasOAuthServer = Object.values(manifest.mcp_servers ?? {}).some(
|
|
615
678
|
(server) => server.auth?.type === "oauth"
|
|
616
679
|
);
|
|
@@ -628,6 +691,168 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
628
691
|
}
|
|
629
692
|
});
|
|
630
693
|
|
|
694
|
+
// src/runnable/tool.ts
|
|
695
|
+
function validateInput(input, schema, toolId) {
|
|
696
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
697
|
+
throw new Error(
|
|
698
|
+
`[ryu-sdk] Tool "${toolId}" input must be an object, got ${JSON.stringify(input)}`
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
const record = input;
|
|
702
|
+
for (const requiredKey of schema.required ?? []) {
|
|
703
|
+
if (!(requiredKey in record)) {
|
|
704
|
+
throw new Error(
|
|
705
|
+
`[ryu-sdk] Tool "${toolId}" input missing required field "${requiredKey}"`
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
710
|
+
if (!(key in record)) {
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
const value = record[key];
|
|
714
|
+
if (!checkType(value, prop.type)) {
|
|
715
|
+
throw new Error(
|
|
716
|
+
`[ryu-sdk] Tool "${toolId}" input field "${key}" expected type "${prop.type}", got ${JSON.stringify(value)}`
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
function checkType(value, type) {
|
|
722
|
+
switch (type) {
|
|
723
|
+
case "string":
|
|
724
|
+
return typeof value === "string";
|
|
725
|
+
case "number":
|
|
726
|
+
case "integer":
|
|
727
|
+
return typeof value === "number";
|
|
728
|
+
case "boolean":
|
|
729
|
+
return typeof value === "boolean";
|
|
730
|
+
case "array":
|
|
731
|
+
return Array.isArray(value);
|
|
732
|
+
case "object":
|
|
733
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
734
|
+
default:
|
|
735
|
+
return false;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
function defineTool(options) {
|
|
739
|
+
const { description, id, name, schema, run } = options;
|
|
740
|
+
const code = `return await (${run.toString()})(input, host);`;
|
|
741
|
+
return {
|
|
742
|
+
id,
|
|
743
|
+
name,
|
|
744
|
+
kind: "tool",
|
|
745
|
+
schema,
|
|
746
|
+
...description === void 0 ? {} : { description },
|
|
747
|
+
code,
|
|
748
|
+
run(input, ctx) {
|
|
749
|
+
validateInput(input, schema, id);
|
|
750
|
+
return run(input, ctx);
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
function inlineToolRunnable(tool, options) {
|
|
755
|
+
return {
|
|
756
|
+
id: tool.id,
|
|
757
|
+
name: tool.name,
|
|
758
|
+
kind: "tool",
|
|
759
|
+
config: {
|
|
760
|
+
slug: tool.id,
|
|
761
|
+
backend: "inline_deno",
|
|
762
|
+
code: tool.code,
|
|
763
|
+
input_schema: tool.schema,
|
|
764
|
+
...options?.description === void 0 ? tool.description === void 0 ? {} : { description: tool.description } : { description: options.description },
|
|
765
|
+
...options?.outputSchema ? { output_schema: options.outputSchema } : {},
|
|
766
|
+
...options?.annotations ? { annotations: options.annotations } : {},
|
|
767
|
+
...options?.action === void 0 ? {} : { action: options.action },
|
|
768
|
+
...options?.needsApproval === void 0 ? {} : { needs_approval: options.needsApproval }
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/runnable/action.ts
|
|
774
|
+
function deriveAnnotations(effect, annotations) {
|
|
775
|
+
const resolved = {
|
|
776
|
+
...annotations,
|
|
777
|
+
readOnlyHint: annotations?.readOnlyHint ?? effect === "read",
|
|
778
|
+
destructiveHint: annotations?.destructiveHint ?? effect === "mutate"
|
|
779
|
+
};
|
|
780
|
+
if (effect === "read" && resolved.destructiveHint) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
"[ryu-sdk] read actions cannot set annotations.destructiveHint=true"
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
if (effect === "mutate" && resolved.readOnlyHint) {
|
|
786
|
+
throw new Error(
|
|
787
|
+
"[ryu-sdk] mutate actions cannot set annotations.readOnlyHint=true"
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
return resolved;
|
|
791
|
+
}
|
|
792
|
+
function actionManifestEntry(action) {
|
|
793
|
+
const options = {
|
|
794
|
+
action: true,
|
|
795
|
+
annotations: action.annotations,
|
|
796
|
+
description: action.description,
|
|
797
|
+
needsApproval: action.needsApproval,
|
|
798
|
+
...action.outputSchema ? { outputSchema: action.outputSchema } : {}
|
|
799
|
+
};
|
|
800
|
+
return inlineToolRunnable(action, options);
|
|
801
|
+
}
|
|
802
|
+
function actionToManifest(action, options) {
|
|
803
|
+
const grants = [.../* @__PURE__ */ new Set([...options.grants ?? [], "tool:execute"])];
|
|
804
|
+
const raw = {
|
|
805
|
+
id: options.id,
|
|
806
|
+
name: options.name ?? action.name,
|
|
807
|
+
version: options.version,
|
|
808
|
+
runnables: [actionManifestEntry(action)],
|
|
809
|
+
permission_grants: grants,
|
|
810
|
+
activation_events: [...options.activationEvents ?? ["*"]],
|
|
811
|
+
targets: [...options.targets ?? []]
|
|
812
|
+
};
|
|
813
|
+
const result = PluginManifestSchema.safeParse(raw);
|
|
814
|
+
if (!result.success) {
|
|
815
|
+
const first = result.error.issues[0];
|
|
816
|
+
const field = first?.path.join(".") ?? "unknown";
|
|
817
|
+
const message = first?.message ?? "validation failed";
|
|
818
|
+
throw new Error(
|
|
819
|
+
`[ryu-sdk] action manifest validation failed at '${field}': ${message}`
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
return result.data;
|
|
823
|
+
}
|
|
824
|
+
function defineAction(options) {
|
|
825
|
+
const annotations = deriveAnnotations(options.effect, options.annotations);
|
|
826
|
+
const tool = defineTool({
|
|
827
|
+
description: options.description,
|
|
828
|
+
id: options.id,
|
|
829
|
+
name: options.name,
|
|
830
|
+
run: options.run,
|
|
831
|
+
schema: options.schema
|
|
832
|
+
});
|
|
833
|
+
const action = {
|
|
834
|
+
...tool,
|
|
835
|
+
action: true,
|
|
836
|
+
annotations,
|
|
837
|
+
description: options.description,
|
|
838
|
+
effect: options.effect,
|
|
839
|
+
needsApproval: options.needsApproval ?? false,
|
|
840
|
+
...options.outputSchema ? { outputSchema: options.outputSchema } : {},
|
|
841
|
+
toManifest(manifestOptions) {
|
|
842
|
+
return actionToManifest(action, manifestOptions);
|
|
843
|
+
},
|
|
844
|
+
toMcpTool(context) {
|
|
845
|
+
return {
|
|
846
|
+
name: action.id,
|
|
847
|
+
description: action.description,
|
|
848
|
+
inputSchema: action.schema,
|
|
849
|
+
run: (input) => action.run(input, context)
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
return action;
|
|
854
|
+
}
|
|
855
|
+
|
|
631
856
|
// src/runnable/agent.ts
|
|
632
857
|
var CAPABILITY_SLOTS = ["rag", "memory", "tts", "stt"];
|
|
633
858
|
function lowerChatSlot(chat) {
|
|
@@ -772,6 +997,13 @@ function withWidgetRenderGrant(grants, widgets) {
|
|
|
772
997
|
}
|
|
773
998
|
return out;
|
|
774
999
|
}
|
|
1000
|
+
function withToolExecuteGrant(grants, tools) {
|
|
1001
|
+
const out = [...grants];
|
|
1002
|
+
if (tools.some((tool) => tool.runnable !== void 0) && !out.includes("tool:execute")) {
|
|
1003
|
+
out.push("tool:execute");
|
|
1004
|
+
}
|
|
1005
|
+
return out;
|
|
1006
|
+
}
|
|
775
1007
|
function appToolId(server, name) {
|
|
776
1008
|
return `${server}.${name}`;
|
|
777
1009
|
}
|
|
@@ -786,7 +1018,9 @@ function defineApp(options) {
|
|
|
786
1018
|
for (const spec of options.tools) {
|
|
787
1019
|
const isRender = spec.accessible !== true;
|
|
788
1020
|
const id = appToolId(server, spec.name);
|
|
1021
|
+
const executable = spec.runnable ? inlineToolRunnable(spec.runnable) : void 0;
|
|
789
1022
|
const config = {
|
|
1023
|
+
...executable?.config ?? {},
|
|
790
1024
|
slug: id,
|
|
791
1025
|
description: spec.description,
|
|
792
1026
|
widget: isRender,
|
|
@@ -820,7 +1054,7 @@ function defineApp(options) {
|
|
|
820
1054
|
hook_events: [],
|
|
821
1055
|
composer_controls: [],
|
|
822
1056
|
settings_tabs: [],
|
|
823
|
-
slash_commands: [],
|
|
1057
|
+
slash_commands: options.slashCommands ?? [],
|
|
824
1058
|
sidebar_sections: [],
|
|
825
1059
|
sidebar_buttons: [],
|
|
826
1060
|
dock_panels: [],
|
|
@@ -838,6 +1072,7 @@ function defineApp(options) {
|
|
|
838
1072
|
pi_extensions: [],
|
|
839
1073
|
output_styles: [],
|
|
840
1074
|
message_actions: [],
|
|
1075
|
+
selection_actions: [],
|
|
841
1076
|
widgets
|
|
842
1077
|
};
|
|
843
1078
|
const raw = {
|
|
@@ -851,15 +1086,15 @@ function defineApp(options) {
|
|
|
851
1086
|
// Core gates widget promotion on declared-AND-enabled-AND-granted, and a
|
|
852
1087
|
// missing grant fails as `DeniedNoGrant` — which is an `info!` log and
|
|
853
1088
|
// nothing else. The widget silently renders as plain text, with no error
|
|
854
|
-
// in the UI and nothing pointing at the manifest.
|
|
855
|
-
// through `defineApp` hit that, because the only fix was a grant string
|
|
856
|
-
// the templates never mention and the builder never added; the one
|
|
857
|
-
// working example on disk hand-writes it.
|
|
1089
|
+
// in the UI and nothing pointing at the manifest.
|
|
858
1090
|
//
|
|
859
1091
|
// Added only when there is a widget to render, and unioned rather than
|
|
860
1092
|
// overwritten so an author's own `grants` list survives and re-declaring
|
|
861
1093
|
// it is not an error.
|
|
862
|
-
permission_grants:
|
|
1094
|
+
permission_grants: withToolExecuteGrant(
|
|
1095
|
+
withWidgetRenderGrant(options.grants ?? [], widgets),
|
|
1096
|
+
options.tools
|
|
1097
|
+
),
|
|
863
1098
|
activation_events: options.activationEvents ?? ["*"],
|
|
864
1099
|
contributes,
|
|
865
1100
|
// `targets: []` means EVERY surface, so an app that declares none is
|
|
@@ -1046,6 +1281,31 @@ var PRIMITIVE_BINDINGS = {
|
|
|
1046
1281
|
method: "background.stop",
|
|
1047
1282
|
grant: "background:control"
|
|
1048
1283
|
},
|
|
1284
|
+
"storage.get": {
|
|
1285
|
+
transport: "bridge",
|
|
1286
|
+
method: "storage.get",
|
|
1287
|
+
grant: "storage:kv"
|
|
1288
|
+
},
|
|
1289
|
+
"storage.set": {
|
|
1290
|
+
transport: "bridge",
|
|
1291
|
+
method: "storage.set",
|
|
1292
|
+
grant: "storage:kv"
|
|
1293
|
+
},
|
|
1294
|
+
"storage.delete": {
|
|
1295
|
+
transport: "bridge",
|
|
1296
|
+
method: "storage.delete",
|
|
1297
|
+
grant: "storage:kv"
|
|
1298
|
+
},
|
|
1299
|
+
"storage.keys": {
|
|
1300
|
+
transport: "bridge",
|
|
1301
|
+
method: "storage.keys",
|
|
1302
|
+
grant: "storage:kv"
|
|
1303
|
+
},
|
|
1304
|
+
"storage.compareAndSet": {
|
|
1305
|
+
transport: "bridge",
|
|
1306
|
+
method: "storage.compareAndSet",
|
|
1307
|
+
grant: "storage:kv"
|
|
1308
|
+
},
|
|
1049
1309
|
// Host-direct media data-path (the host holds the node token; returns data: URLs).
|
|
1050
1310
|
"image.generate": {
|
|
1051
1311
|
transport: "direct",
|
|
@@ -1088,6 +1348,13 @@ function createPrimitives(transport) {
|
|
|
1088
1348
|
process_id: input.processId
|
|
1089
1349
|
})
|
|
1090
1350
|
},
|
|
1351
|
+
storage: {
|
|
1352
|
+
get: (input) => transport.bridge("storage.get", input),
|
|
1353
|
+
set: (input) => transport.bridge("storage.set", input).then(() => void 0),
|
|
1354
|
+
delete: (input) => transport.bridge("storage.delete", input).then(() => void 0),
|
|
1355
|
+
keys: (input) => transport.bridge("storage.keys", input ?? {}).then((value) => Array.isArray(value) ? value : []),
|
|
1356
|
+
compareAndSet: (input) => transport.bridge("storage.compareAndSet", input)
|
|
1357
|
+
},
|
|
1091
1358
|
rag: {
|
|
1092
1359
|
retrieve: (input) => brokerCall(transport, "rag", "retrieve", input),
|
|
1093
1360
|
embed: (input) => brokerCall(transport, "rag", "embed", input),
|
|
@@ -1146,66 +1413,6 @@ function defineSkill(options) {
|
|
|
1146
1413
|
};
|
|
1147
1414
|
}
|
|
1148
1415
|
|
|
1149
|
-
// src/runnable/tool.ts
|
|
1150
|
-
function validateInput(input, schema, toolId) {
|
|
1151
|
-
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
1152
|
-
throw new Error(
|
|
1153
|
-
`[ryu-sdk] Tool "${toolId}" input must be an object, got ${JSON.stringify(input)}`
|
|
1154
|
-
);
|
|
1155
|
-
}
|
|
1156
|
-
const record = input;
|
|
1157
|
-
for (const requiredKey of schema.required ?? []) {
|
|
1158
|
-
if (!(requiredKey in record)) {
|
|
1159
|
-
throw new Error(
|
|
1160
|
-
`[ryu-sdk] Tool "${toolId}" input missing required field "${requiredKey}"`
|
|
1161
|
-
);
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1165
|
-
if (!(key in record)) {
|
|
1166
|
-
continue;
|
|
1167
|
-
}
|
|
1168
|
-
const value = record[key];
|
|
1169
|
-
if (!checkType(value, prop.type)) {
|
|
1170
|
-
throw new Error(
|
|
1171
|
-
`[ryu-sdk] Tool "${toolId}" input field "${key}" expected type "${prop.type}", got ${JSON.stringify(value)}`
|
|
1172
|
-
);
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
function checkType(value, type) {
|
|
1177
|
-
switch (type) {
|
|
1178
|
-
case "string":
|
|
1179
|
-
return typeof value === "string";
|
|
1180
|
-
case "number":
|
|
1181
|
-
case "integer":
|
|
1182
|
-
return typeof value === "number";
|
|
1183
|
-
case "boolean":
|
|
1184
|
-
return typeof value === "boolean";
|
|
1185
|
-
case "array":
|
|
1186
|
-
return Array.isArray(value);
|
|
1187
|
-
case "object":
|
|
1188
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1189
|
-
default:
|
|
1190
|
-
return false;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
function defineTool(options) {
|
|
1194
|
-
const { id, name, schema, run } = options;
|
|
1195
|
-
const code = `return await (${run.toString()})(input, host);`;
|
|
1196
|
-
return {
|
|
1197
|
-
id,
|
|
1198
|
-
name,
|
|
1199
|
-
kind: "tool",
|
|
1200
|
-
schema,
|
|
1201
|
-
code,
|
|
1202
|
-
run(input, ctx) {
|
|
1203
|
-
validateInput(input, schema, id);
|
|
1204
|
-
return run(input, ctx);
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
1416
|
// src/runnable/workflow.ts
|
|
1210
1417
|
function defineWorkflow(options) {
|
|
1211
1418
|
const { id, name, run } = options;
|
|
@@ -1221,6 +1428,7 @@ function defineWorkflow(options) {
|
|
|
1221
1428
|
PRIMITIVE_BINDINGS,
|
|
1222
1429
|
appToolId,
|
|
1223
1430
|
createPrimitives,
|
|
1431
|
+
defineAction,
|
|
1224
1432
|
defineAgent,
|
|
1225
1433
|
defineApp,
|
|
1226
1434
|
defineSkill,
|
package/dist/runnable.d.cts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
export { ActionAnnotations, ActionEffect, ActionManifestOptions, ActionOptions, ActionRunnable, defineAction } from './action.cjs';
|
|
1
2
|
import { CapabilityReq, PluginManifest } from './manifest.cjs';
|
|
2
|
-
import {
|
|
3
|
-
export { B as BackgroundClient, a as BackgroundProcess, D as DurableClient, E as EnginesClient, G as GatewayClient, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient,
|
|
4
|
-
export { A as AppToolSpec, a as DefineAppOptions, b as appToolId, d as defineApp } from './app-
|
|
3
|
+
import { j as Runnable, k as RunnableContext } from './tool-CgzW92O_.cjs';
|
|
4
|
+
export { B as BackgroundClient, a as BackgroundProcess, D as DurableClient, E as EnginesClient, G as GatewayClient, H as HttpPrimitiveTransportOptions, I as ImageClient, b as InlineToolManifestOptions, J as JsonSchemaProperty, M as MemoryClient, c as MemoryItem, P as PRIMITIVE_BINDINGS, d as PrimitiveBinding, e as PrimitiveTransport, R as RagChunk, f as RagClient, g as RagRerankResult, h as RealtimeClient, i as RealtimeSubscription, l as RyuPrimitives, S as StorageClient, m as SttClient, n as ToolOptions, o as ToolSchema, p as TtsClient, q as createPrimitives, r as defineTool, s as httpPrimitiveTransport } from './tool-CgzW92O_.cjs';
|
|
5
|
+
export { A as AppToolSpec, a as DefineAppOptions, b as appToolId, d as defineApp } from './app-B0Z9Ew_R.cjs';
|
|
6
|
+
import './mcp/server.cjs';
|
|
7
|
+
import './mcp/client.cjs';
|
|
5
8
|
import 'zod';
|
|
6
9
|
import './client-D5U6ssPc.cjs';
|
|
7
10
|
|
package/dist/runnable.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
export { ActionAnnotations, ActionEffect, ActionManifestOptions, ActionOptions, ActionRunnable, defineAction } from './action.js';
|
|
1
2
|
import { CapabilityReq, PluginManifest } from './manifest.js';
|
|
2
|
-
import {
|
|
3
|
-
export { B as BackgroundClient, a as BackgroundProcess, D as DurableClient, E as EnginesClient, G as GatewayClient, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient,
|
|
4
|
-
export { A as AppToolSpec, a as DefineAppOptions, b as appToolId, d as defineApp } from './app-
|
|
3
|
+
import { j as Runnable, k as RunnableContext } from './tool-AjkdFvhE.js';
|
|
4
|
+
export { B as BackgroundClient, a as BackgroundProcess, D as DurableClient, E as EnginesClient, G as GatewayClient, H as HttpPrimitiveTransportOptions, I as ImageClient, b as InlineToolManifestOptions, J as JsonSchemaProperty, M as MemoryClient, c as MemoryItem, P as PRIMITIVE_BINDINGS, d as PrimitiveBinding, e as PrimitiveTransport, R as RagChunk, f as RagClient, g as RagRerankResult, h as RealtimeClient, i as RealtimeSubscription, l as RyuPrimitives, S as StorageClient, m as SttClient, n as ToolOptions, o as ToolSchema, p as TtsClient, q as createPrimitives, r as defineTool, s as httpPrimitiveTransport } from './tool-AjkdFvhE.js';
|
|
5
|
+
export { A as AppToolSpec, a as DefineAppOptions, b as appToolId, d as defineApp } from './app-C-BDJwfG.js';
|
|
6
|
+
import './mcp/server.js';
|
|
7
|
+
import './mcp/client.js';
|
|
5
8
|
import 'zod';
|
|
6
9
|
import './client-D5U6ssPc.js';
|
|
7
10
|
|
package/dist/runnable.js
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineAgent,
|
|
3
3
|
defineSkill,
|
|
4
|
-
defineTool,
|
|
5
4
|
defineWorkflow
|
|
6
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BC3A7HMO.js";
|
|
7
6
|
import {
|
|
8
7
|
appToolId,
|
|
9
8
|
defineApp
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-IEUQ3CDG.js";
|
|
9
|
+
} from "./chunk-SN2QBJUF.js";
|
|
12
10
|
import {
|
|
13
11
|
PRIMITIVE_BINDINGS,
|
|
14
12
|
createPrimitives,
|
|
15
13
|
httpPrimitiveTransport
|
|
16
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ZTJWBRUL.js";
|
|
15
|
+
import {
|
|
16
|
+
defineAction
|
|
17
|
+
} from "./chunk-4TPUZDTI.js";
|
|
18
|
+
import {
|
|
19
|
+
defineTool
|
|
20
|
+
} from "./chunk-QYFUNJOH.js";
|
|
21
|
+
import "./chunk-NZKVOSC2.js";
|
|
17
22
|
import "./chunk-IKEDLLFY.js";
|
|
18
23
|
export {
|
|
19
24
|
PRIMITIVE_BINDINGS,
|
|
20
25
|
appToolId,
|
|
21
26
|
createPrimitives,
|
|
27
|
+
defineAction,
|
|
22
28
|
defineAgent,
|
|
23
29
|
defineApp,
|
|
24
30
|
defineSkill,
|
|
@@ -278,6 +278,36 @@ interface BackgroundClient {
|
|
|
278
278
|
process_id: string;
|
|
279
279
|
}>;
|
|
280
280
|
}
|
|
281
|
+
/** Durable app-owned key/value state (`storage:kv` via the host bridge). */
|
|
282
|
+
interface StorageClient {
|
|
283
|
+
/** Atomically replace a value when it still equals `expected`. */
|
|
284
|
+
compareAndSet(input: {
|
|
285
|
+
expected: string | null;
|
|
286
|
+
key: string;
|
|
287
|
+
namespace?: string;
|
|
288
|
+
value: string | null;
|
|
289
|
+
}): Promise<boolean>;
|
|
290
|
+
/** Delete one value. */
|
|
291
|
+
delete(input: {
|
|
292
|
+
key: string;
|
|
293
|
+
namespace?: string;
|
|
294
|
+
}): Promise<void>;
|
|
295
|
+
/** Read one value; missing keys return `null`. */
|
|
296
|
+
get(input: {
|
|
297
|
+
key: string;
|
|
298
|
+
namespace?: string;
|
|
299
|
+
}): Promise<string | null>;
|
|
300
|
+
/** List keys in an app-owned namespace. */
|
|
301
|
+
keys(input?: {
|
|
302
|
+
namespace?: string;
|
|
303
|
+
}): Promise<string[]>;
|
|
304
|
+
/** Write one string value. JSON can be encoded by the app when needed. */
|
|
305
|
+
set(input: {
|
|
306
|
+
key: string;
|
|
307
|
+
namespace?: string;
|
|
308
|
+
value: string;
|
|
309
|
+
}): Promise<void>;
|
|
310
|
+
}
|
|
281
311
|
/** TTS primitive — speech synthesis (`crates/ryu-tts`). */
|
|
282
312
|
interface TtsClient {
|
|
283
313
|
/**
|
|
@@ -330,6 +360,7 @@ interface RyuPrimitives {
|
|
|
330
360
|
memory: MemoryClient;
|
|
331
361
|
rag: RagClient;
|
|
332
362
|
realtime: RealtimeClient;
|
|
363
|
+
storage: StorageClient;
|
|
333
364
|
stt: SttClient;
|
|
334
365
|
tts: TtsClient;
|
|
335
366
|
}
|
|
@@ -393,6 +424,8 @@ interface RunnableContext {
|
|
|
393
424
|
sessionId?: string;
|
|
394
425
|
/** Signal to abort a long-running run. */
|
|
395
426
|
signal?: AbortSignal;
|
|
427
|
+
/** Durable app-owned KV state, gated by the manifest's `storage:kv` grant. */
|
|
428
|
+
storage?: StorageClient;
|
|
396
429
|
/** STT primitive: transcribe (`crates/ryu-stt`). */
|
|
397
430
|
stt?: SttClient;
|
|
398
431
|
/** TTS primitive: speak (`crates/ryu-tts`). */
|
|
@@ -472,9 +505,13 @@ interface ToolSchema {
|
|
|
472
505
|
required?: string[];
|
|
473
506
|
/** Type is always "object" for a tool's top-level input schema. */
|
|
474
507
|
type: "object";
|
|
508
|
+
/** Preserve additional JSON Schema keywords for Core/MCP consumers. */
|
|
509
|
+
[key: string]: unknown;
|
|
475
510
|
}
|
|
476
511
|
/** Options accepted by `defineTool`. */
|
|
477
512
|
interface ToolOptions<TInput extends Record<string, unknown>, TOutput> {
|
|
513
|
+
/** Optional description surfaced to models and tool discovery. */
|
|
514
|
+
description?: string;
|
|
478
515
|
/** Stable unique identifier (e.g. "tool-web-search"). */
|
|
479
516
|
id: string;
|
|
480
517
|
/** Human-readable display name. */
|
|
@@ -514,6 +551,8 @@ interface ToolRunnable<TInput extends Record<string, unknown> = Record<string, u
|
|
|
514
551
|
* the sandbox form is the second parameter aliased to `host`.
|
|
515
552
|
*/
|
|
516
553
|
readonly code: string;
|
|
554
|
+
/** Optional description surfaced to models and tool discovery. */
|
|
555
|
+
readonly description?: string;
|
|
517
556
|
readonly kind: "tool";
|
|
518
557
|
/** JSON Schema for this tool's input — compatible with Core's ToolInfo.schema. */
|
|
519
558
|
readonly schema: ToolSchema;
|
|
@@ -548,6 +587,19 @@ interface ToolRunnable<TInput extends Record<string, unknown> = Record<string, u
|
|
|
548
587
|
* ```
|
|
549
588
|
*/
|
|
550
589
|
declare function defineTool<TInput extends Record<string, unknown> = Record<string, unknown>, TOutput = unknown>(options: ToolOptions<TInput, TOutput>): ToolRunnable<TInput, TOutput>;
|
|
590
|
+
/** Optional metadata lowered alongside a tool's executable backend. */
|
|
591
|
+
interface InlineToolManifestOptions {
|
|
592
|
+
/** Marks the entry as a semantic Ryu Action. */
|
|
593
|
+
action?: boolean;
|
|
594
|
+
/** MCP-style effect annotations, for example `readOnlyHint`. */
|
|
595
|
+
annotations?: Record<string, boolean | undefined>;
|
|
596
|
+
/** Description shown in Core's unified tool catalog. */
|
|
597
|
+
description?: string;
|
|
598
|
+
/** Force the human approval gate before the tool runs. */
|
|
599
|
+
needsApproval?: boolean;
|
|
600
|
+
/** JSON Schema for the structured result. */
|
|
601
|
+
outputSchema?: Record<string, unknown>;
|
|
602
|
+
}
|
|
551
603
|
/**
|
|
552
604
|
* Convert a {@link ToolRunnable} into a `manifest.json` `kind:"tool"` runnable that
|
|
553
605
|
* ships its `run` body as Core's `inline_deno` backend. The emitted config
|
|
@@ -558,8 +610,6 @@ declare function defineTool<TInput extends Record<string, unknown> = Record<stri
|
|
|
558
610
|
*
|
|
559
611
|
* The plugin must declare the `tool:execute` grant (see `definePlugin`).
|
|
560
612
|
*/
|
|
561
|
-
declare function inlineToolRunnable(tool: ToolRunnable, options?:
|
|
562
|
-
description?: string;
|
|
563
|
-
}): RunnableMeta;
|
|
613
|
+
declare function inlineToolRunnable(tool: Pick<ToolRunnable, "code" | "description" | "id" | "name" | "schema">, options?: InlineToolManifestOptions): RunnableMeta;
|
|
564
614
|
|
|
565
|
-
export { type BackgroundClient as B, type DurableClient as D, type EnginesClient as E, type GatewayClient as G, type HttpPrimitiveTransportOptions as H, type ImageClient as I, type JsonSchemaProperty as J, type MemoryClient as M, PRIMITIVE_BINDINGS as P, type RagChunk as R, type
|
|
615
|
+
export { type BackgroundClient as B, type DurableClient as D, type EnginesClient as E, type GatewayClient as G, type HttpPrimitiveTransportOptions as H, type ImageClient as I, type JsonSchemaProperty as J, type MemoryClient as M, PRIMITIVE_BINDINGS as P, type RagChunk as R, type StorageClient as S, type ToolRunnable as T, type BackgroundProcess as a, type InlineToolManifestOptions as b, type MemoryItem as c, type PrimitiveBinding as d, type PrimitiveTransport as e, type RagClient as f, type RagRerankResult as g, type RealtimeClient as h, type RealtimeSubscription as i, type Runnable as j, type RunnableContext as k, type RyuPrimitives as l, type SttClient as m, type ToolOptions as n, type ToolSchema as o, type TtsClient as p, createPrimitives as q, defineTool as r, httpPrimitiveTransport as s, inlineToolRunnable as t };
|