@ryuhq/sdk 0.0.5

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.
Files changed (61) hide show
  1. package/LICENSE +179 -0
  2. package/README.md +31 -0
  3. package/dist/agent.cjs +761 -0
  4. package/dist/agent.d.cts +3 -0
  5. package/dist/agent.d.ts +3 -0
  6. package/dist/agent.js +23 -0
  7. package/dist/chunk-GXHL5CO7.js +353 -0
  8. package/dist/chunk-KPKMMGVC.js +671 -0
  9. package/dist/chunk-ODFEUVPW.js +100 -0
  10. package/dist/cli.cjs +858 -0
  11. package/dist/cli.d.cts +1 -0
  12. package/dist/cli.d.ts +1 -0
  13. package/dist/cli.js +454 -0
  14. package/dist/index-CEbS1SlS.d.cts +988 -0
  15. package/dist/index-DAxq7Y0R.d.ts +988 -0
  16. package/dist/index.cjs +1900 -0
  17. package/dist/index.d.cts +759 -0
  18. package/dist/index.d.ts +759 -0
  19. package/dist/index.js +771 -0
  20. package/dist/manifest.cjs +399 -0
  21. package/dist/manifest.d.cts +355 -0
  22. package/dist/manifest.d.ts +355 -0
  23. package/dist/manifest.js +38 -0
  24. package/package.json +56 -0
  25. package/src/agent/agent.ts +208 -0
  26. package/src/agent/index.ts +51 -0
  27. package/src/agent/loop.test.ts +261 -0
  28. package/src/agent/loop.ts +259 -0
  29. package/src/agent/model-call.ts +190 -0
  30. package/src/agent/query.ts +40 -0
  31. package/src/agent/tools.ts +295 -0
  32. package/src/builder.ts +473 -0
  33. package/src/cli/dev.test.ts +178 -0
  34. package/src/cli/dev.ts +425 -0
  35. package/src/cli.ts +390 -0
  36. package/src/contracts-lockstep.test.ts +77 -0
  37. package/src/generated/plugin-manifest.ts +1121 -0
  38. package/src/index.ts +141 -0
  39. package/src/manifest.test.ts +610 -0
  40. package/src/manifest.ts +589 -0
  41. package/src/mcp/bridge.test.ts +196 -0
  42. package/src/mcp/client.ts +253 -0
  43. package/src/mcp/fixture-server.ts +23 -0
  44. package/src/mcp/server.ts +351 -0
  45. package/src/model/client.test.ts +107 -0
  46. package/src/model/client.ts +179 -0
  47. package/src/model/gateway.ts +41 -0
  48. package/src/plugin/ryu-plugin.ts +191 -0
  49. package/src/runnable/agent.ts +338 -0
  50. package/src/runnable/app.ts +233 -0
  51. package/src/runnable/index.ts +61 -0
  52. package/src/runnable/primitives-hostapi.test.ts +73 -0
  53. package/src/runnable/primitives.test.ts +286 -0
  54. package/src/runnable/primitives.ts +610 -0
  55. package/src/runnable/runnable-types.ts +113 -0
  56. package/src/runnable/runnable.test.ts +397 -0
  57. package/src/runnable/skill.ts +60 -0
  58. package/src/runnable/tool.ts +260 -0
  59. package/src/runnable/turn-hook.test.ts +81 -0
  60. package/src/runnable/turn-hook.ts +191 -0
  61. package/src/runnable/workflow.ts +76 -0
@@ -0,0 +1,759 @@
1
+ import { R as Runnable, a as RunnableContext, T as ToolRunnable } from './index-CEbS1SlS.cjs';
2
+ export { A as Agent, b as AgentConfig, c as AgentEvent, d as AgentTool, C as ChatDelta, e as ChatMessage, f as ChatResult, D as DurableClient, E as Endpoint, g as EnginesClient, G as GatewayClient, h as GenerateResult, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient, i as MemoryItem, j as ModelClient, k as ModelClientOptions, P as PRIMITIVE_BINDINGS, l as PrimitiveBinding, m as PrimitiveTransport, Q as QueryInput, n as QueryOptions, o as RagChunk, p as RagClient, q as RagRerankResult, r as RealtimeClient, s as RealtimeSubscription, t as RemoteToolRef, u as RyuPrimitives, S as SttClient, v as ToolOptions, w as ToolSchema, x as TtsClient, y as createAgent, z as createPrimitives, B as defineModel, F as defineTool, K as httpPrimitiveTransport, L as inlineToolRunnable, N as query, O as ryuTool } from './index-CEbS1SlS.cjs';
3
+ import { Requires, Surface, PluginManifest, RunnableMeta, CompanionSurface, CapabilityReq, TurnHookContribution } from './manifest.cjs';
4
+ export { AppDependency, AppDependencySchema, CapabilityReqSchema, CompanionSurfaceSchema, Contributes, PluginManifestSchema, RequiresSchema, RunnableKind, RunnableKindSchema, RunnableMetaSchema, SurfaceSchema, ToolAppConfig, ToolAppConfigSchema, WidgetContribution, WidgetContributionSchema, coreManifestJsonSchema, validateManifestStrict, validatePluginId } from './manifest.cjs';
5
+ import 'zod';
6
+
7
+ /**
8
+ * Ryu App authoring factory — `defineApp`.
9
+ *
10
+ * A "Ryu App" bundles one or more tools whose results render an interactive
11
+ * widget inline in chat (the ChatGPT-Apps-style surface). `defineApp` assembles a
12
+ * complete `plugin.json` `PluginManifest` from a declarative description, deriving
13
+ * the render-vs-companion split exactly the way Core's in-process provider does
14
+ * (`apps/core/src/sidecar/mcp/apps/mod.rs` `tools()`):
15
+ *
16
+ * - A **render** tool (`accessible` unset/false) produces the widget: it gets a
17
+ * `contributes.widgets[]` entry binding its id to the app's
18
+ * `ui://widget/<slug>.html` template, and its runnable config carries
19
+ * `widget:true` plus `invoking`/`invoked` status labels.
20
+ * - A **companion** tool (`accessible:true`) is a call target a mounted widget
21
+ * may invoke: it carries `widget_accessible:true` and gets no widget template.
22
+ *
23
+ * v1 boundary: this is **declarative pass-through only** — there is no `run`
24
+ * handler. Third-party tool code execution needs the plugin runtime (out of
25
+ * scope); the widget renders from `window.openai.toolInput`/`toolOutput` and Core
26
+ * echoes the validated arguments as `structuredContent`. `ryu pack` bundles the
27
+ * `uiEntry` source into the manifest's `ui_code`.
28
+ */
29
+
30
+ /** One tool a Ryu App declares. */
31
+ interface AppToolSpec {
32
+ /**
33
+ * True when this is a **companion** tool — a call target a mounted widget may
34
+ * `callTool`. False/unset makes it a **render** tool that produces the widget.
35
+ */
36
+ accessible?: boolean;
37
+ /** Human-readable description the model reads when choosing the tool. */
38
+ description: string;
39
+ /** JSON Schema object describing the tool's arguments. Optional. */
40
+ inputSchema?: Record<string, unknown>;
41
+ /** Status label shown when a render tool finishes (e.g. `"Chart ready"`). */
42
+ invoked?: string;
43
+ /** Status label shown while a render tool runs (e.g. `"Plotting chart…"`). */
44
+ invoking?: string;
45
+ /** Tool name (unqualified). The wire id is `<server>__<name>`. */
46
+ name: string;
47
+ }
48
+ /**
49
+ * The `requires` block as an AUTHOR writes it: both members optional. Distinct
50
+ * from the parsed {@link Requires} (where zod has applied its `[]` defaults, so
51
+ * both are present).
52
+ */
53
+ interface DefineAppRequires {
54
+ /** Plugins that must be installed + enabled before this app enables. */
55
+ apps?: Requires["apps"];
56
+ /**
57
+ * Abstract capability edges the broker binds to a provider at enable time
58
+ * (`[{ capability: "rag" }]`). This is what composable agent slots lower to.
59
+ */
60
+ capabilities?: Requires["capabilities"];
61
+ /** Grants implied by those dependencies (declaration only). */
62
+ grants?: string[];
63
+ }
64
+ /** Options for {@link defineApp}. */
65
+ interface DefineAppOptions {
66
+ /** VS-Code-style activation events. Empty = eager (default `["*"]`). */
67
+ activationEvents?: string[];
68
+ /** Default widget display mode (`inline` | `fullscreen` | `pip`). */
69
+ displayMode?: string;
70
+ /** Permission grants the app declares it needs (e.g. `["mcp:web_search"]`). */
71
+ grants?: string[];
72
+ /** Reverse-domain plugin id (e.g. `"com.example.checklist"`). */
73
+ id: string;
74
+ /** Widget MIME dialect. Defaults to `text/html+skybridge`. */
75
+ mime?: string;
76
+ /**
77
+ * Plugin-to-plugin dependencies. Core auto-enables them (in dependency order)
78
+ * before this app, and refuses to disable one while this app still needs it.
79
+ * Omit for the common case (no dependencies) — the key is then absent from the
80
+ * emitted manifest entirely.
81
+ */
82
+ requires?: DefineAppRequires;
83
+ /** MCP server namespace for the tool ids. Defaults to `slug`. */
84
+ server?: string;
85
+ /**
86
+ * App slug — used to build the widget uri (`ui://widget/<slug>.html`) and, when
87
+ * `server` is omitted, the MCP server namespace that qualifies each tool id.
88
+ */
89
+ slug: string;
90
+ /**
91
+ * Host surfaces this app runs on. **Omitted/empty = every surface** (the
92
+ * backward-compatible default); it never means "hidden".
93
+ */
94
+ targets?: Surface[];
95
+ /** Human-readable display name shown in the app store / launcher. */
96
+ title: string;
97
+ /** The tools this app exposes (at least one render tool is expected). */
98
+ tools: AppToolSpec[];
99
+ /**
100
+ * Source entry (relative to the manifest dir) for the widget UI. `ryu pack`
101
+ * bundles it into the manifest's `ui_code` so Core can serve the widget HTML.
102
+ */
103
+ uiEntry: string;
104
+ /** Semver version string (e.g. `"1.0.0"`). */
105
+ version: string;
106
+ }
107
+ /** Build a fully-qualified tool id from a server namespace and tool name. */
108
+ declare function appToolId(server: string, name: string): string;
109
+ /**
110
+ * Assemble a `plugin.json` manifest for a Ryu App. The result matches Core's
111
+ * `PluginManifest` serde shape (validated through `PluginManifestSchema`) and can
112
+ * be written to disk, packed with `ryu pack`, or published with `ryu publish`.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * import { defineApp } from "@ryuhq/sdk"
117
+ *
118
+ * const manifest = defineApp({
119
+ * id: "com.example.checklist",
120
+ * title: "Checklist",
121
+ * version: "1.0.0",
122
+ * slug: "checklist",
123
+ * uiEntry: "src/checklist.tsx",
124
+ * tools: [
125
+ * { name: "render", description: "Render a checklist", invoking: "Building…", invoked: "Ready" },
126
+ * { name: "toggle", description: "Toggle an item", accessible: true },
127
+ * ],
128
+ * })
129
+ * ```
130
+ */
131
+ declare function defineApp(options: DefineAppOptions): PluginManifest;
132
+
133
+ /**
134
+ * Ryu SDK typed builders — one builder per RunnableKind plus a PluginBuilder that
135
+ * assembles a complete, validated `plugin.json` manifest.
136
+ *
137
+ * Each builder follows a fluent interface: construct, chain setter calls, then
138
+ * call `.build()` to get a validated result. Invalid manifests throw a
139
+ * descriptive `Error` — never a silent fallback.
140
+ *
141
+ * Engine/model fields are typed as `string` throughout. No provider union is
142
+ * used so adding a new provider never requires an SDK change.
143
+ */
144
+
145
+ /** Base builder shared by all Runnable kinds. */
146
+ declare class RunnableBuilder {
147
+ protected _id: string;
148
+ protected _name: string;
149
+ id(value: string): this;
150
+ name(value: string): this;
151
+ }
152
+ /** Builds an Agent `RunnableMeta` entry. */
153
+ declare class AgentBuilder extends RunnableBuilder {
154
+ build(): RunnableMeta;
155
+ }
156
+ /** Builds a Workflow `RunnableMeta` entry. */
157
+ declare class WorkflowBuilder extends RunnableBuilder {
158
+ build(): RunnableMeta;
159
+ }
160
+ /** Builds a Tool `RunnableMeta` entry. */
161
+ declare class ToolBuilder extends RunnableBuilder {
162
+ build(): RunnableMeta;
163
+ }
164
+ /** Builds a Skill `RunnableMeta` entry. */
165
+ declare class SkillBuilder extends RunnableBuilder {
166
+ build(): RunnableMeta;
167
+ }
168
+ /** Create an AgentBuilder. */
169
+ declare const agent: () => AgentBuilder;
170
+ /** Create a WorkflowBuilder. */
171
+ declare const workflow: () => WorkflowBuilder;
172
+ /** Create a ToolBuilder. */
173
+ declare const tool: () => ToolBuilder;
174
+ /** Create a SkillBuilder. */
175
+ declare const skill: () => SkillBuilder;
176
+ /**
177
+ * Fluent builder for a complete `plugin.json` Plugin manifest. Produces a
178
+ * validated `PluginManifest` on `.build()` or throws a descriptive `Error`
179
+ * naming the first invalid field.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * import { PluginBuilder, agent, tool } from "@ryuhq/sdk/builder"
184
+ *
185
+ * const manifest = new PluginBuilder()
186
+ * .id("com.example.my-plugin")
187
+ * .name("My Plugin")
188
+ * .version("1.0.0")
189
+ * .runnable(agent().id("agent-main").name("Main Agent").build())
190
+ * .runnable(tool().id("tool-search").name("Web Search").build())
191
+ * .grant("mcp:web_search")
192
+ * .companion({ label: "My Plugin", icon: "sparkles", shortcut: "ctrl+shift+m" })
193
+ * .build()
194
+ * ```
195
+ */
196
+ declare class PluginBuilder {
197
+ private _id;
198
+ private _name;
199
+ private _version;
200
+ private readonly _runnables;
201
+ private readonly _grants;
202
+ private _companion;
203
+ private readonly _dependencies;
204
+ private readonly _requiredCapabilities;
205
+ private readonly _requiredGrants;
206
+ private readonly _targets;
207
+ /** Set the reverse-domain app id (e.g. `"com.example.my-app"`). */
208
+ id(value: string): this;
209
+ /** Set the human-readable display name. */
210
+ name(value: string): this;
211
+ /** Set the semver version string (e.g. `"1.0.0"`). */
212
+ version(value: string): this;
213
+ /** Append a pre-built `RunnableMeta` (from any per-kind builder). */
214
+ runnable(meta: RunnableMeta): this;
215
+ /** Declare a permission grant (e.g. `"mcp:web_search"`). */
216
+ grant(permission: string): this;
217
+ /** Set an optional Companion surface descriptor. */
218
+ companion(surface: CompanionSurface): this;
219
+ /**
220
+ * Declare a **plugin-to-plugin dependency**: `id` must be installed and is
221
+ * auto-enabled (in dependency order) before this plugin enables.
222
+ *
223
+ * `minVersion` is a MINIMUM — a bare `"1.2.0"` means `">=1.2.0"`, so an
224
+ * installed `2.0.0` satisfies it (comparator syntax like `">=1.2, <2"` is
225
+ * honoured verbatim).
226
+ */
227
+ dependsOn(id: string, minVersion?: string): this;
228
+ /**
229
+ * Declare a permission grant implied by this plugin's dependencies
230
+ * (`requires.grants`). Declaration only — the Gateway remains the sole
231
+ * authority on what a grant allows. Use {@link PluginBuilder.grant} for the
232
+ * grants this plugin needs in its own right.
233
+ */
234
+ requiredGrant(permission: string): this;
235
+ /**
236
+ * Declare an abstract **capability** edge (`requires.capabilities`) the broker
237
+ * resolves to a bound provider at enable time — e.g. `requiresCapability("rag")`.
238
+ * Distinct from a specific-plugin dependency: a capability edge lets the
239
+ * binding registry choose the provider. `minVersion` is a MINIMUM (`"1.2.0"`
240
+ * = `">=1.2.0"`).
241
+ */
242
+ requiresCapability(capability: string, minVersion?: string): this;
243
+ /**
244
+ * Restrict this plugin to a host surface (`"desktop"`, `"island"`, …).
245
+ * Declaring NO target is the default and means **every** surface.
246
+ */
247
+ target(surface: Surface): this;
248
+ /**
249
+ * Validate and return the assembled `PluginManifest`. Throws an `Error` with
250
+ * the failing field name and message when validation fails.
251
+ */
252
+ build(): PluginManifest;
253
+ }
254
+ /**
255
+ * Fluent builder for a Ryu App — a `plugin.json` whose tools render interactive
256
+ * widgets inline in chat. Delegates to {@link defineApp} on `.build()`, so it
257
+ * derives the render-vs-companion split and validates through
258
+ * `PluginManifestSchema` (throwing a descriptive `Error` on bad input) exactly
259
+ * like the factory.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * import { app } from "@ryuhq/sdk/builder"
264
+ *
265
+ * const manifest = app()
266
+ * .id("com.example.checklist")
267
+ * .title("Checklist")
268
+ * .version("1.0.0")
269
+ * .slug("checklist")
270
+ * .uiEntry("src/checklist.tsx")
271
+ * .tool({ name: "render", description: "Render a checklist", invoking: "Building…" })
272
+ * .tool({ name: "toggle", description: "Toggle an item", accessible: true })
273
+ * .build()
274
+ * ```
275
+ */
276
+ declare class AppBuilder {
277
+ private _id;
278
+ private _title;
279
+ private _version;
280
+ private _slug;
281
+ private _server;
282
+ private _displayMode;
283
+ private _mime;
284
+ private _uiEntry;
285
+ private readonly _grants;
286
+ private readonly _activationEvents;
287
+ private readonly _tools;
288
+ private readonly _dependencies;
289
+ private readonly _requiredCapabilities;
290
+ private readonly _requiredGrants;
291
+ private readonly _targets;
292
+ /** Set the reverse-domain app id (e.g. `"com.example.checklist"`). */
293
+ id(value: string): this;
294
+ /** Set the human-readable display name. */
295
+ title(value: string): this;
296
+ /** Set the semver version string (e.g. `"1.0.0"`). */
297
+ version(value: string): this;
298
+ /** Set the app slug (drives `ui://widget/<slug>.html` and the server default). */
299
+ slug(value: string): this;
300
+ /** Override the MCP server namespace for tool ids (defaults to the slug). */
301
+ server(value: string): this;
302
+ /** Set the default widget display mode (`inline` | `fullscreen` | `pip`). */
303
+ displayMode(value: string): this;
304
+ /** Override the widget MIME dialect (defaults to `text/html+skybridge`). */
305
+ mime(value: string): this;
306
+ /** Set the widget UI source entry `ryu pack` bundles into `ui_code`. */
307
+ uiEntry(value: string): this;
308
+ /** Declare a permission grant (e.g. `"mcp:web_search"`). */
309
+ grant(permission: string): this;
310
+ /** Add a VS-Code-style activation event (empty = eager `["*"]`). */
311
+ activationEvent(event: string): this;
312
+ /** Append a tool spec (render tool unless `accessible:true`). */
313
+ tool(spec: AppToolSpec): this;
314
+ /**
315
+ * Declare a **plugin-to-plugin dependency** (auto-enabled, in dependency order,
316
+ * before this app). `minVersion` is a MINIMUM (`"1.2.0"` = `">=1.2.0"`).
317
+ */
318
+ dependsOn(id: string, minVersion?: string): this;
319
+ /** Declare a grant implied by this app's dependencies (`requires.grants`). */
320
+ requiredGrant(permission: string): this;
321
+ /**
322
+ * Declare an abstract **capability** edge (`requires.capabilities`) the broker
323
+ * resolves to a bound provider at enable time — e.g. `requiresCapability("rag")`.
324
+ * Distinct from a specific-plugin dependency: a capability edge lets the
325
+ * binding registry choose the provider. `minVersion` is a MINIMUM (`"1.2.0"`
326
+ * = `">=1.2.0"`).
327
+ */
328
+ requiresCapability(capability: string, minVersion?: string): this;
329
+ /** Restrict this app to a host surface. No target = every surface. */
330
+ target(surface: Surface): this;
331
+ /**
332
+ * Validate and return the assembled `PluginManifest`. Throws an `Error` naming
333
+ * the failing field when validation fails.
334
+ */
335
+ build(): PluginManifest;
336
+ }
337
+ /** Create an AppBuilder. */
338
+ declare const app: () => AppBuilder;
339
+
340
+ /**
341
+ * Gateway configuration + egress enforcement for the Ryu SDK model client.
342
+ *
343
+ * Rust-cored: every function here delegates to the `@ryuhq/sdk-native` addon, so
344
+ * the gateway URL/token resolution and the direct-provider egress blocklist are
345
+ * the exact same implementation (`crates/ryu-sdk/src/gateway.rs`) used by the
346
+ * Go/Python bindings and Core itself — one source of truth, no drift.
347
+ */
348
+ /** Default base URL for the local Ryu gateway — matches Core's DEFAULT_GATEWAY_URL. */
349
+ declare const DEFAULT_GATEWAY_URL = "http://127.0.0.1:7981";
350
+ /**
351
+ * Resolve the effective gateway base URL.
352
+ *
353
+ * Resolution order (in the Rust core):
354
+ * 1. `RYU_GATEWAY_URL` env var (when non-empty).
355
+ * 2. `DEFAULT_GATEWAY_URL`.
356
+ */
357
+ declare function resolveGatewayUrl(): string;
358
+ /**
359
+ * Resolve the optional gateway bearer token (`RYU_GATEWAY_TOKEN`), or
360
+ * `undefined` when unset/empty.
361
+ */
362
+ declare function resolveGatewayToken(): string | undefined;
363
+ /**
364
+ * Validate that `baseUrl` is an allowed egress target. Throws a descriptive
365
+ * `Error` (from the Rust core) when the URL matches a known direct-provider
366
+ * pattern, enforcing the BYOK-at-the-gateway rule.
367
+ */
368
+ declare function assertAllowedEgressUrl(baseUrl: string): void;
369
+
370
+ /**
371
+ * defineAgent — factory for Runnable agents.
372
+ *
373
+ * An agent is a Runnable that drives a multi-turn model loop. It may reference a
374
+ * workflow as a named tool by including a Runnable with kind="workflow" in its
375
+ * `tools` list; the agent's run() implementation calls it like any other tool.
376
+ *
377
+ * All model calls must go through `ctx.gateway` — no direct provider imports.
378
+ *
379
+ * ## Composable primitive slots (the "Pokémon card" model, program §6b)
380
+ *
381
+ * `defineAgent` additionally accepts swappable-provider SLOTS —
382
+ * `defineAgent({ chat, rag, memory, tools, tts, stt })` — where each slot picks
383
+ * a provider for one attribute of the card. They **lower** to the manifest:
384
+ * - `chat` → the agent `RunnableMeta.config` (model / engine / persona);
385
+ * - `rag` / `memory` / `tts` / `stt` → `requires.capabilities` edges the
386
+ * capability broker binds to a provider (with an optional explicit override);
387
+ * - `tools` → the tool ids the agent exposes.
388
+ *
389
+ * The slots are ADDITIVE: the classic `defineAgent({ id, name, run })` signature
390
+ * is unchanged. When `run` is omitted, a thin default run drives the `chat` slot
391
+ * through `ctx.gateway` (never a direct provider).
392
+ */
393
+
394
+ /**
395
+ * A capability-backed slot (rag / memory / tts / stt). Written as:
396
+ * - `true` — require the capability; the broker/registry picks the provider;
397
+ * - `"com.acme.graphrag"` — bind this explicit provider app id;
398
+ * - `{ provider?, minVersion? }` — provider override and/or a version floor.
399
+ */
400
+ type CapabilitySlot = boolean | string | {
401
+ provider?: string;
402
+ minVersion?: string;
403
+ };
404
+ /**
405
+ * The chat/model slot — the agent's own, swappable model config. Written as a
406
+ * model-id string shorthand or the full object. Every field is a `string`; no
407
+ * provider union, so a new provider never needs an SDK change.
408
+ */
409
+ type ChatSlot = string | {
410
+ /** Model id (swappable). */
411
+ model?: string;
412
+ /** Engine id (e.g. `"llamacpp"`, `"openai-compat"`). */
413
+ engine?: string;
414
+ /** System persona / instructions. */
415
+ persona?: string;
416
+ /** Preference key Core resolves to a model id (swappable, not hardcoded). */
417
+ modelPrefKey?: string;
418
+ };
419
+ /** The composable slots an agent card declares. All optional. */
420
+ interface AgentSlots {
421
+ /** The chat/model slot (model + engine + persona). */
422
+ chat?: ChatSlot;
423
+ /** Memory provider slot → `requires.capabilities: [{ capability: "memory" }]`. */
424
+ memory?: CapabilitySlot;
425
+ /** RAG provider slot → `requires.capabilities: [{ capability: "rag" }]`. */
426
+ rag?: CapabilitySlot;
427
+ /** STT provider slot → `requires.capabilities: [{ capability: "stt" }]`. */
428
+ stt?: CapabilitySlot;
429
+ /** Tools the agent exposes — Runnables (workflows/tools) or bare tool ids. */
430
+ tools?: readonly (Runnable | string)[];
431
+ /** TTS provider slot → `requires.capabilities: [{ capability: "tts" }]`. */
432
+ tts?: CapabilitySlot;
433
+ }
434
+ /** Options accepted by `defineAgent`. */
435
+ interface AgentOptions<TInput, TOutput> extends AgentSlots {
436
+ /** Stable unique identifier (e.g. "agent-researcher"). */
437
+ id: string;
438
+ /** Human-readable display name. */
439
+ name: string;
440
+ /**
441
+ * The agent's run implementation. OPTIONAL when slots are declared — a
442
+ * `chat`-slot default is synthesized (drives `ctx.gateway`). All model calls
443
+ * MUST go through `ctx.gateway`.
444
+ */
445
+ run?(input: TInput, ctx: RunnableContext): Promise<TOutput>;
446
+ }
447
+ /**
448
+ * The lowered "card": the swappable slots resolved to manifest-ready pieces —
449
+ * the persona/model config plus the `requires.capabilities` edges. This is what
450
+ * makes the Pokémon-card model literal in code.
451
+ */
452
+ interface AgentCard {
453
+ /** Lowered capability edges for `requires.capabilities`. */
454
+ capabilities: CapabilityReq[];
455
+ /** Engine id from the `chat` slot. */
456
+ engine?: string;
457
+ /** Model id from the `chat` slot. */
458
+ model?: string;
459
+ /** Preference key from the `chat` slot. */
460
+ modelPrefKey?: string;
461
+ /** Persona/instructions from the `chat` slot. */
462
+ persona?: string;
463
+ /** Explicit provider bindings by capability (a slot that named a provider). */
464
+ providers: Record<string, string>;
465
+ /** Tool ids the agent exposes. */
466
+ tools: string[];
467
+ }
468
+ /** A defined agent: a Runnable plus its lowered card + a manifest lowering. */
469
+ interface AgentRunnable<TInput = unknown, TOutput = unknown> extends Runnable<TInput, TOutput> {
470
+ /** The lowered slot card (empty edges when no slots were declared). */
471
+ readonly card: AgentCard;
472
+ /**
473
+ * Lower this agent (card + run identity) to a single-agent `plugin.json`
474
+ * `PluginManifest`: the agent `RunnableMeta` carries the persona/model
475
+ * config; `requires.capabilities` carries the slot edges. Throws if the
476
+ * assembled manifest is invalid.
477
+ */
478
+ toManifest(options: AgentManifestOptions): PluginManifest;
479
+ }
480
+ /** Options for {@link AgentRunnable.toManifest}. */
481
+ interface AgentManifestOptions {
482
+ /** Extra permission grants beyond those implied by slots. */
483
+ grants?: string[];
484
+ /** Reverse-domain plugin id (e.g. `"com.acme.researcher"`). */
485
+ id: string;
486
+ /** Display name (defaults to the agent's name). */
487
+ name?: string;
488
+ /** Semver version (e.g. `"1.0.0"`). */
489
+ version: string;
490
+ }
491
+ /**
492
+ * Create a Runnable agent.
493
+ *
494
+ * The returned value satisfies `Runnable<TInput, TOutput>` with `kind = "agent"`
495
+ * and additionally exposes the lowered {@link AgentCard} + a `toManifest()`
496
+ * lowering, so a slot-composed agent round-trips to a valid `plugin.json`.
497
+ *
498
+ * @example Classic (unchanged, back-compat):
499
+ * ```ts
500
+ * const a = defineAgent({
501
+ * id: "agent-researcher",
502
+ * name: "Researcher",
503
+ * async run({ query }, ctx) {
504
+ * const r = await ctx.gateway.chat([{ role: "user", content: query }]);
505
+ * return { answer: r.content };
506
+ * },
507
+ * });
508
+ * ```
509
+ *
510
+ * @example Composable slots (the Pokémon card):
511
+ * ```ts
512
+ * const cmo = defineAgent({
513
+ * id: "agent-cmo",
514
+ * name: "CMO",
515
+ * chat: { model: "gpt-4o", persona: "You are a CMO." },
516
+ * rag: true, // requires.capabilities: [{ capability: "rag" }]
517
+ * memory: { minVersion: "1.2" },
518
+ * tts: "com.acme.elevenlabs", // explicit provider override
519
+ * });
520
+ * const manifest = cmo.toManifest({ id: "com.acme.cmo", version: "1.0.0" });
521
+ * ```
522
+ */
523
+ declare function defineAgent<TInput = unknown, TOutput = unknown>(options: AgentOptions<TInput, TOutput>): AgentRunnable<TInput, TOutput>;
524
+
525
+ /**
526
+ * defineSkill — factory for Runnable skills.
527
+ *
528
+ * A skill is a prompt-template / capability block that is reusable across
529
+ * agents and workflows. Like a tool it is stateless, but its primary purpose
530
+ * is to encapsulate a reusable prompt pattern rather than a side-effectful
531
+ * function.
532
+ *
533
+ * All model calls must go through `ctx.gateway` — no direct provider imports.
534
+ */
535
+
536
+ /** Options accepted by `defineSkill`. */
537
+ interface SkillOptions<TInput, TOutput> {
538
+ /** Stable unique identifier (e.g. "skill-summarise"). */
539
+ id: string;
540
+ /** Human-readable display name. */
541
+ name: string;
542
+ /**
543
+ * The skill's run implementation.
544
+ *
545
+ * Skills typically build a prompt from `input` and call `ctx.gateway.chat()`
546
+ * to get a model response, then return structured output. All model calls
547
+ * MUST go through `ctx.gateway`.
548
+ */
549
+ run(input: TInput, ctx: RunnableContext): Promise<TOutput>;
550
+ }
551
+ /**
552
+ * Create a Runnable skill.
553
+ *
554
+ * The returned value satisfies the `Runnable<TInput, TOutput>` interface with
555
+ * `kind = "skill"`.
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * const summariseSkill = defineSkill({
560
+ * id: "skill-summarise",
561
+ * name: "Summarise",
562
+ * async run({ text }, ctx) {
563
+ * const result = await ctx.gateway.chat([
564
+ * { role: "user", content: `Summarise the following:\n\n${text}` },
565
+ * ]);
566
+ * return { summary: result.content };
567
+ * },
568
+ * });
569
+ * ```
570
+ */
571
+ declare function defineSkill<TInput = unknown, TOutput = unknown>(options: SkillOptions<TInput, TOutput>): Runnable<TInput, TOutput>;
572
+
573
+ /**
574
+ * Turn-hook + plugin authoring factories.
575
+ *
576
+ * A turn hook is plugin-authored logic that runs after each assistant turn in
577
+ * Ryu's Core plugin sandbox (`apps/core/src/plugin_host/`). The hook reaches Core
578
+ * only through capability-gated `host` functions and returns a directive. This is
579
+ * what makes features like double-check and goal real, installable plugins.
580
+ *
581
+ * `defineTurnHook` serializes your typed `run(ctx, host)` function to the `code`
582
+ * string the sandbox executes. IMPORTANT: the function must be **self-contained**
583
+ * — it runs in a fresh sandbox with only `ctx` and `host` in scope, so it cannot
584
+ * capture outer variables, imports, or closures (same constraint as a Web Worker
585
+ * body). Reference only `ctx`, `host`, and language built-ins.
586
+ */
587
+
588
+ /** The context a `post_assistant_turn` hook receives. */
589
+ interface HookContext {
590
+ /** The agent that produced the turn. */
591
+ agent_id?: string;
592
+ /** The conversation id (also the natural per-conversation storage key). */
593
+ conversation_id?: string;
594
+ /** Per-request plugin flags (e.g. a composer toggle): `{ "<pluginId>": true }`. */
595
+ flags: Record<string, boolean>;
596
+ /** Recent transcript (oldest → newest). */
597
+ transcript: Array<{
598
+ role: string;
599
+ content: string;
600
+ }>;
601
+ }
602
+ /** Arguments to a `host.sideModel` call. */
603
+ interface SideModelArgs {
604
+ /** Reasoning effort, forwarded when non-empty. */
605
+ effort?: string;
606
+ /** Explicit model id (wins over `model_pref_key`). */
607
+ model?: string;
608
+ /** A preference key Core resolves to a model id (swappable, not hardcoded). */
609
+ model_pref_key?: string;
610
+ /** The user prompt for the side model. Required. */
611
+ prompt: string;
612
+ /** Optional system prompt. */
613
+ system?: string;
614
+ }
615
+ /** The capability bridge available to a hook (gated by manifest grants). */
616
+ interface HostApi {
617
+ /** Captured logging. */
618
+ log(...args: unknown[]): void;
619
+ /** One non-streaming gateway completion. Grant: `hook:side-model`. */
620
+ sideModel(args: SideModelArgs): Promise<string>;
621
+ /** The plugin's own namespaced KV store. Grant: `storage:kv`. */
622
+ storage: {
623
+ get(key: string): Promise<string | null>;
624
+ set(key: string, value: unknown): Promise<boolean>;
625
+ delete(key: string): Promise<boolean>;
626
+ keys(): Promise<string[]>;
627
+ };
628
+ }
629
+ /** What a hook asks the chat path to do after the assistant turn. */
630
+ type HookDirective = {
631
+ kind: "none";
632
+ } | {
633
+ kind: "note";
634
+ text: string;
635
+ } | {
636
+ kind: "continue";
637
+ text: string;
638
+ };
639
+ /** A typed hook implementation: `(ctx, host) => directive`. */
640
+ type HookRun = (ctx: HookContext, host: HostApi) => HookDirective | Promise<HookDirective>;
641
+ interface DefineTurnHookOptions {
642
+ /** Stable id for this hook, unique within the plugin. */
643
+ id: string;
644
+ /** Turn boundary (default `"post_assistant_turn"`). */
645
+ on?: string;
646
+ /** The hook body. Must be self-contained (no captured variables). */
647
+ run: HookRun;
648
+ }
649
+ /**
650
+ * Build a turn-hook contribution from a typed `run` function. The function source
651
+ * is serialized into the sandbox `code` string and invoked with `ctx`/`host` at
652
+ * run time.
653
+ */
654
+ declare function defineTurnHook(options: DefineTurnHookOptions): TurnHookContribution;
655
+ interface DefinePluginOptions {
656
+ /** Activation events (default `["*"]` — driven by the enabled flag). */
657
+ activationEvents?: string[];
658
+ /** Declarative composer widgets (toggle/chip), passed verbatim to the desktop. */
659
+ composerControls?: Record<string, unknown>[];
660
+ /** Capability grants the hooks need (e.g. `["hook:side-model", "storage:kv"]`). */
661
+ grants?: string[];
662
+ /** Reverse-domain id (e.g. `"com.example.my-plugin"`). */
663
+ id: string;
664
+ /** Display name. */
665
+ name: string;
666
+ /**
667
+ * Plugin-to-plugin dependencies. Core auto-enables them (in dependency order)
668
+ * before this plugin, and refuses to disable one while this plugin needs it.
669
+ * Omit for the common case — the key is then absent from the emitted manifest.
670
+ */
671
+ requires?: DefineAppRequires;
672
+ /** Declarative settings tabs (model pickers, fields), passed verbatim. */
673
+ settingsTabs?: Record<string, unknown>[];
674
+ /** Declarative slash commands, passed verbatim. */
675
+ slashCommands?: Record<string, unknown>[];
676
+ /**
677
+ * Host surfaces this plugin runs on. **Omitted/empty = every surface** (the
678
+ * backward-compatible default); it never means "hidden".
679
+ */
680
+ targets?: Surface[];
681
+ /**
682
+ * Inline tools the plugin ships — each a {@link ToolRunnable} from `defineTool`
683
+ * whose `run` body is bundled as Core's `inline_deno` backend (registered as
684
+ * `app__<tool.id>`). Shipping any tool auto-adds the `tool:execute` grant.
685
+ */
686
+ tools?: ToolRunnable[];
687
+ /** Turn hooks the plugin contributes. */
688
+ turnHooks?: TurnHookContribution[];
689
+ /** Semver version (e.g. `"1.0.0"`). */
690
+ version: string;
691
+ }
692
+ /**
693
+ * Assemble a `plugin.json` manifest for a turn-hook plugin. The result matches
694
+ * Core's `PluginManifest` serde shape and can be written to disk or validated via
695
+ * `validateManifestStrict`.
696
+ */
697
+ declare function definePlugin(options: DefinePluginOptions): PluginManifest;
698
+
699
+ /**
700
+ * defineWorkflow — factory for Runnable workflows.
701
+ *
702
+ * A workflow orchestrates agents (and other Runnables) as sequential steps.
703
+ * It exposes the peer relationship described in packages/sdk/README.md §2:
704
+ * a workflow may list an agent as a step and call it via its run() method.
705
+ *
706
+ * All model calls must go through `ctx.gateway` — no direct provider imports.
707
+ */
708
+
709
+ /**
710
+ * A single step inside a workflow definition.
711
+ *
712
+ * A step is any `Runnable` — most commonly an agent, but may also be a tool
713
+ * or a nested workflow (allowing composition without a strict hierarchy).
714
+ */
715
+ type WorkflowStep<TStepInput = unknown, TStepOutput = unknown> = Runnable<TStepInput, TStepOutput>;
716
+ /** Options accepted by `defineWorkflow`. */
717
+ interface WorkflowOptions<TInput, TOutput> {
718
+ /** Stable unique identifier (e.g. "workflow-report"). */
719
+ id: string;
720
+ /** Human-readable display name. */
721
+ name: string;
722
+ /**
723
+ * The workflow's run implementation.
724
+ *
725
+ * May call any step via `step.run(input, ctx)`. All model calls that
726
+ * steps make MUST go through `ctx.gateway`.
727
+ */
728
+ run(input: TInput, ctx: RunnableContext): Promise<TOutput>;
729
+ /**
730
+ * Optional list of Runnables this workflow orchestrates as steps.
731
+ *
732
+ * An agent may be listed here so the workflow can invoke it by calling
733
+ * `step.run(input, ctx)` — this is the peer relationship described in
734
+ * packages/sdk/README.md §2.
735
+ */
736
+ steps?: readonly Runnable[];
737
+ }
738
+ /**
739
+ * Create a Runnable workflow.
740
+ *
741
+ * The returned value satisfies the `Runnable<TInput, TOutput>` interface with
742
+ * `kind = "workflow"`.
743
+ *
744
+ * @example
745
+ * ```ts
746
+ * const myWorkflow = defineWorkflow({
747
+ * id: "workflow-report",
748
+ * name: "Report Workflow",
749
+ * steps: [researchAgent],
750
+ * async run({ topic }, ctx) {
751
+ * const { answer } = await researchAgent.run({ query: topic }, ctx);
752
+ * return { report: answer };
753
+ * },
754
+ * });
755
+ * ```
756
+ */
757
+ declare function defineWorkflow<TInput = unknown, TOutput = unknown>(options: WorkflowOptions<TInput, TOutput>): Runnable<TInput, TOutput>;
758
+
759
+ export { AgentBuilder, type AgentCard, type AgentManifestOptions, type AgentOptions, type AgentRunnable, type AgentSlots, AppBuilder, type AppToolSpec, CapabilityReq, type CapabilitySlot, type ChatSlot, CompanionSurface, DEFAULT_GATEWAY_URL, type DefineAppOptions, type DefineAppRequires, type DefinePluginOptions, type DefineTurnHookOptions, type HookContext, type HookDirective, type HookRun, type HostApi, PluginBuilder, PluginManifest, Requires, Runnable, RunnableContext, RunnableMeta, type SideModelArgs, SkillBuilder, type SkillOptions, Surface, ToolBuilder, ToolRunnable, TurnHookContribution, WorkflowBuilder, type WorkflowOptions, type WorkflowStep, agent, app, appToolId, assertAllowedEgressUrl, defineAgent, defineApp, definePlugin, defineSkill, defineTurnHook, defineWorkflow, resolveGatewayToken, resolveGatewayUrl, skill, tool, workflow };