@yaklabs-ai/plugin-sdk 0.49.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ it under the name your plugin code actually imports:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.49.0"
16
+ "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.50.0"
17
17
  }
18
18
  }
19
19
  ```
@@ -62,7 +62,7 @@ Every tool the entrypoint registers is declared in the manifest too:
62
62
  "description": "Greets people by name.",
63
63
  "version": "0.1.0",
64
64
  "namespace": "widgets",
65
- "compatibility": { "sdk": "^0.49.0" },
65
+ "compatibility": { "sdk": "^0.50.0" },
66
66
  "targets": {
67
67
  "kay": {
68
68
  "agent": {
@@ -139,6 +139,7 @@ naming both versions, instead of loading it and finding no `activate`.
139
139
  | `@bonsai/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
140
140
  | `@bonsai/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
141
141
  | `@bonsai/plugin-sdk/uri` | Sessionless resource caller types, revision digest and unavailable fallback, from 0.49.0 |
142
+ | `@bonsai/plugin-sdk/endpoints` | Sessionless cross-plugin endpoint caller and outcome types, from 0.50.0 |
142
143
  | `@bonsai/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
143
144
  | `@bonsai/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
144
145
  | `@bonsai/plugin-sdk/time` | `Temporal` (Bonsai's own instance) and the time-zone helpers, from 0.13.6 |
@@ -150,7 +151,7 @@ naming both versions, instead of loading it and finding no `activate`.
150
151
  | `@bonsai/plugin-sdk/system-one` | The types and error class for `api.systemOne` / `app.systemOne`, from 0.13.8 |
151
152
  | `@bonsai/plugin-sdk/zod` | `z` (the host's in the daemon), on an entry with no other import, from 0.13.9 |
152
153
 
153
- A plugin that imports these subpaths declares the current supported SDK range (`^0.49.0`).
154
+ A plugin that imports these subpaths declares the current supported SDK range (`^0.50.0`).
154
155
  The rows record when each subpath appeared, not retained runtime compatibility. `vendored-mcp` builds the plugin's URI module (its link cards and help); hosting the
155
156
  vendor's MCP server itself is a separate host decision: Bonsai hosts it once a person approves
156
157
  the plugin's `mcp.host-server` grant for that server's name and URL. A server that needs an OAuth
@@ -158,7 +159,7 @@ sign-in names one of the plugin's auth services in `authService`; that service m
158
159
  one `delegated` scheme, which Bonsai uses to sign the person in to the server. Bonsai declares that
159
160
  scheme at runtime; the plugin's code must not declare it again. From 0.16.2 a plugin's code can also
160
161
  call the server's tools through `api.vendoredMcp.port(<server>)`, typed by this subpath's
161
- `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.49.0`).
162
+ `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.50.0`).
162
163
 
163
164
  From 0.13.10 the manifest schema carries two facts Bonsai reads for its own plugins only; another
164
165
  plugin's are ignored, with a load diagnostic. An `external-cli` auth scheme's `cli` says how Bonsai
@@ -228,18 +229,19 @@ A newer floor always has a release: every change to the rule set publishes a
228
229
  version of this package as it lands, so "update and re-run" is never blocked on
229
230
  someone remembering to cut one. If the numbers differ, a newer version exists.
230
231
 
231
- ## Sessionless calls (0.49.0)
232
+ ## Sessionless calls (resources from 0.49.0, endpoints from 0.50.0)
232
233
 
233
- Both backend targets expose `uri.read/list/search/write/edit/delete`. Calls return native
234
- resources, bytes and revisions. Exact `uri.call` grants name the canonical scheme and verb;
235
- declaring a dependency grants no authority. Declared cross-plugin endpoint calls are deferred
236
- to the next slice of #15758.
234
+ Both backend targets expose `uri.read/list/search/write/edit/delete` and
235
+ `endpoints.invokePlugin(providerPluginId, endpointLocalId, payload, { signal })`.
236
+ URI calls return native resources, bytes and revisions. Endpoint calls return an unknown JSON
237
+ value on success or a structured failure, including `denied` when the exact grant is absent.
238
+ Provider schemas remain authoritative; declaring a dependency grants no authority.
237
239
 
238
240
  `app.memory` and its `KayAppMemory*` types are removed. Use complete `memory://` addresses
239
241
  through `app.uri`, parse returned Markdown in the consuming plugin, and retain the read's
240
242
  revision (or `contentDigest` from `/uri`) for edits. The old `memory.read` and `memory.write`
241
- grants do not authorize the replacement scheme-and-verb calls. Earlier SDK contracts are
242
- refused; migrate and declare `^0.49.0`.
243
+ grants do not authorize the replacement scheme-and-verb calls. Contracts before 0.49.0 are
244
+ refused; migrate and declare `^0.50.0`. The current host also serves the 0.49.0 resource contract.
243
245
 
244
246
  ## What this package is, and is not, at runtime
245
247
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@yaklabs-ai/plugin-sdk",
4
- "version": "0.49.0",
4
+ "version": "0.50.0",
5
5
  "target": "npm",
6
6
  "firstPartyLicense": "MIT",
7
7
  "bundled": [
@@ -2453,8 +2453,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2453
2453
  * types; callers use the resource surface instead. Previously admitted SDK contracts are no
2454
2454
  * longer served because they included app.memory on notebook hosts. No compatibility alias
2455
2455
  * restores it; callers migrate and declare ^0.49.0.
2456
+ *
2457
+ * 0.50.0 adds explicit cross-plugin endpoint calls on both backend targets. The URI-only 0.49.0
2458
+ * contract remains served.
2456
2459
  */
2457
- declare const KAY_PLUGIN_SDK_VERSION: "0.49.0";
2460
+ declare const KAY_PLUGIN_SDK_VERSION: "0.50.0";
2458
2461
 
2459
2462
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2460
2463
 
@@ -2467,46 +2470,9 @@ declare interface KayAgentCompiler {
2467
2470
  bundleBrowser(request: KayBrowserBundleRequest, sources: KayBrowserSources): Promise<KayBrowserBundle>;
2468
2471
  }
2469
2472
 
2470
- /**
2471
- * The plugin-facing `kay.agent` own-endpoint call: a plugin's agent part calls an endpoint its own
2472
- * `kay.app` part registered. SDK 0.17.3; a plugin that calls it declares `compatibility.sdk`
2473
- * `^0.19.0`.
2474
- *
2475
- * A plugin's two parts load as separate modules and share no memory, so this is how agent code
2476
- * reaches state its app part keeps (a worker, a database). The manifest says which endpoints the
2477
- * agent part may call: the `kay.app` target declares the endpoint with a `register` grant, and
2478
- * `permissions.byTarget["kay.agent"].endpoints` lists it with `invoke`. No other plugin's endpoint
2479
- * is nameable.
2480
- *
2481
- * An endpoint whose only `invoke` grant is the plugin's own `kay.agent` target is not reachable
2482
- * from Bonsai's surfaces (its pages and runtime clients), so an action the agent takes after the
2483
- * session's approval card cannot be taken around it.
2484
- */
2485
- /** Why an {@link KayAgentEndpoints.invoke} call produced no value. */
2486
- declare type KayAgentEndpointFailureReason =
2487
- /** The manifest grants this plugin's `kay.agent` target no `invoke` on this endpoint. */
2488
- "not-declared"
2489
- /** The plugin's `kay.app` part is not running, or registered no handler for it. */
2490
- | "unavailable"
2491
- /** The handler did not answer within the host's fixed deadline (10 seconds). It may still finish. */
2492
- | "timed-out"
2493
- /** The caller's `signal` aborted. The handler may still finish. */
2494
- | "cancelled"
2495
- /** The handler threw; `message` is its error's message. */
2496
- | "failed"
2497
- /** The request or the handler's response does not match the endpoint's declared schema. */
2498
- | "invalid";
2499
-
2500
- declare type KayAgentEndpointOutcome = {
2501
- readonly ok: true;
2502
- readonly value: unknown;
2503
- } | {
2504
- readonly ok: false;
2505
- readonly reason: KayAgentEndpointFailureReason;
2506
- readonly message: string;
2507
- };
2473
+ declare type KayAgentEndpointOutcome = PluginEndpointOutcome;
2508
2474
 
2509
- declare interface KayAgentEndpoints {
2475
+ declare interface KayAgentEndpoints extends PluginEndpointCaller {
2510
2476
  /**
2511
2477
  * Call `endpoint`, the local id this plugin's manifest declares on its `kay.app` target. Never
2512
2478
  * rejects: every failure is an outcome. Nothing is queued: when the app part is not running the
@@ -2772,10 +2738,9 @@ declare interface KayAgentPluginApi {
2772
2738
  */
2773
2739
  readonly vendoredMcp: KayAgentVendoredMcp;
2774
2740
  /**
2775
- * Calls the endpoints this plugin's own `kay.app` part registered and the manifest grants this
2776
- * target `invoke` on, by local id. Never another plugin's. Every failure is an outcome, never a
2777
- * rejection; the host fixes a 10-second deadline. Always present; a host with no app part
2778
- * answers each call `unavailable`. See {@link KayAgentEndpoints} (SDK 0.17.3).
2741
+ * `invoke` calls this plugin's own declared app endpoint by local id. `invokePlugin` names a
2742
+ * provider plugin explicitly and checks this target's exact `endpoints.invoke` claim. Every
2743
+ * failure is an outcome; unavailable providers are never queued.
2779
2744
  */
2780
2745
  readonly endpoints: KayAgentEndpoints;
2781
2746
  /**
@@ -4417,6 +4382,28 @@ declare interface PluginDelegatedServiceEntry {
4417
4382
  /** One rule id from {@link PLUGIN_DISCLOSURE_RULES}. */
4418
4383
  export declare type PluginDisclosureRule = (typeof PLUGIN_DISCLOSURE_RULES)[number];
4419
4384
 
4385
+ /** Sessionless JSON calls to another plugin's declared, publicly reachable endpoint. */
4386
+ declare interface PluginEndpointCaller {
4387
+ /**
4388
+ * Never rejects. Both payload and result are validated against the provider's declared schemas.
4389
+ * Nothing is queued or retried. Cancellation and timeouts leave the operation's effect unknown.
4390
+ */
4391
+ invokePlugin(providerPluginId: string, endpointLocalId: string, payload: unknown, options?: {
4392
+ readonly signal?: AbortSignal;
4393
+ }): Promise<PluginEndpointOutcome>;
4394
+ }
4395
+
4396
+ declare type PluginEndpointFailureReason = "not-declared" | "unavailable" | "timed-out" | "cancelled" | "failed" | "invalid" | "denied";
4397
+
4398
+ declare type PluginEndpointOutcome = {
4399
+ readonly ok: true;
4400
+ readonly value: unknown;
4401
+ } | {
4402
+ readonly ok: false;
4403
+ readonly reason: PluginEndpointFailureReason;
4404
+ readonly message: string;
4405
+ };
4406
+
4420
4407
  declare const PluginEventPublishInput: z.ZodObject<{
4421
4408
  uri: z.ZodString;
4422
4409
  related: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
@@ -737,10 +737,18 @@ function createUnavailableUriCaller(message) {
737
737
  };
738
738
  }
739
739
 
740
+ // packages/plugin-sdk/dist/endpoints.js
741
+ function createUnavailablePluginEndpointCaller(message) {
742
+ return {
743
+ invokePlugin: async () => ({ ok: false, reason: "unavailable", message })
744
+ };
745
+ }
746
+
740
747
  // packages/plugin-sdk/dist/kay-agent/endpoints.js
741
748
  function createUnavailableEndpoints(message) {
742
749
  return {
743
- invoke: async () => ({ ok: false, reason: "unavailable", message })
750
+ invoke: async () => ({ ok: false, reason: "unavailable", message }),
751
+ ...createUnavailablePluginEndpointCaller(message)
744
752
  };
745
753
  }
746
754
 
@@ -0,0 +1,25 @@
1
+ export declare function createUnavailablePluginEndpointCaller(message: string): PluginEndpointCaller;
2
+
3
+ /** Sessionless JSON calls to another plugin's declared, publicly reachable endpoint. */
4
+ export declare interface PluginEndpointCaller {
5
+ /**
6
+ * Never rejects. Both payload and result are validated against the provider's declared schemas.
7
+ * Nothing is queued or retried. Cancellation and timeouts leave the operation's effect unknown.
8
+ */
9
+ invokePlugin(providerPluginId: string, endpointLocalId: string, payload: unknown, options?: {
10
+ readonly signal?: AbortSignal;
11
+ }): Promise<PluginEndpointOutcome>;
12
+ }
13
+
14
+ export declare type PluginEndpointFailureReason = "not-declared" | "unavailable" | "timed-out" | "cancelled" | "failed" | "invalid" | "denied";
15
+
16
+ export declare type PluginEndpointOutcome = {
17
+ readonly ok: true;
18
+ readonly value: unknown;
19
+ } | {
20
+ readonly ok: false;
21
+ readonly reason: PluginEndpointFailureReason;
22
+ readonly message: string;
23
+ };
24
+
25
+ export { }
@@ -0,0 +1,9 @@
1
+ // packages/plugin-sdk/dist/endpoints.js
2
+ function createUnavailablePluginEndpointCaller(message) {
3
+ return {
4
+ invokePlugin: async () => ({ ok: false, reason: "unavailable", message })
5
+ };
6
+ }
7
+ export {
8
+ createUnavailablePluginEndpointCaller
9
+ };
@@ -2507,8 +2507,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2507
2507
  * types; callers use the resource surface instead. Previously admitted SDK contracts are no
2508
2508
  * longer served because they included app.memory on notebook hosts. No compatibility alias
2509
2509
  * restores it; callers migrate and declare ^0.49.0.
2510
+ *
2511
+ * 0.50.0 adds explicit cross-plugin endpoint calls on both backend targets. The URI-only 0.49.0
2512
+ * contract remains served.
2510
2513
  */
2511
- declare const KAY_PLUGIN_SDK_VERSION: "0.49.0";
2514
+ declare const KAY_PLUGIN_SDK_VERSION: "0.50.0";
2512
2515
 
2513
2516
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2514
2517
 
@@ -2518,46 +2521,9 @@ declare interface KayAgentCompiler {
2518
2521
  bundleBrowser(request: KayBrowserBundleRequest, sources: KayBrowserSources): Promise<KayBrowserBundle>;
2519
2522
  }
2520
2523
 
2521
- /**
2522
- * The plugin-facing `kay.agent` own-endpoint call: a plugin's agent part calls an endpoint its own
2523
- * `kay.app` part registered. SDK 0.17.3; a plugin that calls it declares `compatibility.sdk`
2524
- * `^0.19.0`.
2525
- *
2526
- * A plugin's two parts load as separate modules and share no memory, so this is how agent code
2527
- * reaches state its app part keeps (a worker, a database). The manifest says which endpoints the
2528
- * agent part may call: the `kay.app` target declares the endpoint with a `register` grant, and
2529
- * `permissions.byTarget["kay.agent"].endpoints` lists it with `invoke`. No other plugin's endpoint
2530
- * is nameable.
2531
- *
2532
- * An endpoint whose only `invoke` grant is the plugin's own `kay.agent` target is not reachable
2533
- * from Bonsai's surfaces (its pages and runtime clients), so an action the agent takes after the
2534
- * session's approval card cannot be taken around it.
2535
- */
2536
- /** Why an {@link KayAgentEndpoints.invoke} call produced no value. */
2537
- declare type KayAgentEndpointFailureReason =
2538
- /** The manifest grants this plugin's `kay.agent` target no `invoke` on this endpoint. */
2539
- "not-declared"
2540
- /** The plugin's `kay.app` part is not running, or registered no handler for it. */
2541
- | "unavailable"
2542
- /** The handler did not answer within the host's fixed deadline (10 seconds). It may still finish. */
2543
- | "timed-out"
2544
- /** The caller's `signal` aborted. The handler may still finish. */
2545
- | "cancelled"
2546
- /** The handler threw; `message` is its error's message. */
2547
- | "failed"
2548
- /** The request or the handler's response does not match the endpoint's declared schema. */
2549
- | "invalid";
2550
-
2551
- declare type KayAgentEndpointOutcome = {
2552
- readonly ok: true;
2553
- readonly value: unknown;
2554
- } | {
2555
- readonly ok: false;
2556
- readonly reason: KayAgentEndpointFailureReason;
2557
- readonly message: string;
2558
- };
2524
+ declare type KayAgentEndpointOutcome = PluginEndpointOutcome;
2559
2525
 
2560
- declare interface KayAgentEndpoints {
2526
+ declare interface KayAgentEndpoints extends PluginEndpointCaller {
2561
2527
  /**
2562
2528
  * Call `endpoint`, the local id this plugin's manifest declares on its `kay.app` target. Never
2563
2529
  * rejects: every failure is an outcome. Nothing is queued: when the app part is not running the
@@ -2823,10 +2789,9 @@ declare interface KayAgentPluginApi {
2823
2789
  */
2824
2790
  readonly vendoredMcp: KayAgentVendoredMcp;
2825
2791
  /**
2826
- * Calls the endpoints this plugin's own `kay.app` part registered and the manifest grants this
2827
- * target `invoke` on, by local id. Never another plugin's. Every failure is an outcome, never a
2828
- * rejection; the host fixes a 10-second deadline. Always present; a host with no app part
2829
- * answers each call `unavailable`. See {@link KayAgentEndpoints} (SDK 0.17.3).
2792
+ * `invoke` calls this plugin's own declared app endpoint by local id. `invokePlugin` names a
2793
+ * provider plugin explicitly and checks this target's exact `endpoints.invoke` claim. Every
2794
+ * failure is an outcome; unavailable providers are never queued.
2830
2795
  */
2831
2796
  readonly endpoints: KayAgentEndpoints;
2832
2797
  /**
@@ -4432,6 +4397,28 @@ declare interface PluginDelegatedServiceEntry {
4432
4397
  readonly scheme: PluginDelegatedScheme;
4433
4398
  }
4434
4399
 
4400
+ /** Sessionless JSON calls to another plugin's declared, publicly reachable endpoint. */
4401
+ declare interface PluginEndpointCaller {
4402
+ /**
4403
+ * Never rejects. Both payload and result are validated against the provider's declared schemas.
4404
+ * Nothing is queued or retried. Cancellation and timeouts leave the operation's effect unknown.
4405
+ */
4406
+ invokePlugin(providerPluginId: string, endpointLocalId: string, payload: unknown, options?: {
4407
+ readonly signal?: AbortSignal;
4408
+ }): Promise<PluginEndpointOutcome>;
4409
+ }
4410
+
4411
+ declare type PluginEndpointFailureReason = "not-declared" | "unavailable" | "timed-out" | "cancelled" | "failed" | "invalid" | "denied";
4412
+
4413
+ declare type PluginEndpointOutcome = {
4414
+ readonly ok: true;
4415
+ readonly value: unknown;
4416
+ } | {
4417
+ readonly ok: false;
4418
+ readonly reason: PluginEndpointFailureReason;
4419
+ readonly message: string;
4420
+ };
4421
+
4435
4422
  declare const PluginEventPublishInput: z.ZodObject<{
4436
4423
  uri: z.ZodString;
4437
4424
  related: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
@@ -358,15 +358,8 @@ function fauxKayAgentCapabilities() {
358
358
  })
359
359
  })
360
360
  },
361
- // Answers `unavailable` naming itself, keeping the real call's promise never to reject. A test
362
- // that exercises its plugin's own endpoints passes its own handle.
363
- endpoints: {
364
- invoke: async (endpoint) => ({
365
- ok: false,
366
- reason: "unavailable",
367
- message: `endpoints.invoke("${endpoint}") is not wired in this test double`
368
- })
369
- }
361
+ // Uncomposed own and foreign calls keep their outcome contract instead of rejecting.
362
+ endpoints: { invokePlugin: NOT_WIRED, invoke: NOT_WIRED }
370
363
  };
371
364
  }
372
365
  function createTestClock(startMs, options = {}) {
@@ -813,6 +813,8 @@ export declare function createUnavailableCompiler(message: string): KayAgentComp
813
813
  */
814
814
  export declare function createUnavailableEndpoints(message: string): KayAgentEndpoints;
815
815
 
816
+ export declare function createUnavailablePluginEndpointCaller(message: string): PluginEndpointCaller;
817
+
816
818
  export declare function createUnavailableUriCaller(message: string): PluginUriCaller;
817
819
 
818
820
  /** What the module holds at mutation time: a provider revision, the current content, or both. */
@@ -2784,8 +2786,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2784
2786
  * types; callers use the resource surface instead. Previously admitted SDK contracts are no
2785
2787
  * longer served because they included app.memory on notebook hosts. No compatibility alias
2786
2788
  * restores it; callers migrate and declare ^0.49.0.
2789
+ *
2790
+ * 0.50.0 adds explicit cross-plugin endpoint calls on both backend targets. The URI-only 0.49.0
2791
+ * contract remains served.
2787
2792
  */
2788
- declare const KAY_PLUGIN_SDK_VERSION: "0.49.0";
2793
+ declare const KAY_PLUGIN_SDK_VERSION: "0.50.0";
2789
2794
 
2790
2795
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2791
2796
 
@@ -2819,46 +2824,11 @@ export declare interface KayAgentCompiler {
2819
2824
  bundleBrowser(request: KayBrowserBundleRequest, sources: KayBrowserSources): Promise<KayBrowserBundle>;
2820
2825
  }
2821
2826
 
2822
- /**
2823
- * The plugin-facing `kay.agent` own-endpoint call: a plugin's agent part calls an endpoint its own
2824
- * `kay.app` part registered. SDK 0.17.3; a plugin that calls it declares `compatibility.sdk`
2825
- * `^0.19.0`.
2826
- *
2827
- * A plugin's two parts load as separate modules and share no memory, so this is how agent code
2828
- * reaches state its app part keeps (a worker, a database). The manifest says which endpoints the
2829
- * agent part may call: the `kay.app` target declares the endpoint with a `register` grant, and
2830
- * `permissions.byTarget["kay.agent"].endpoints` lists it with `invoke`. No other plugin's endpoint
2831
- * is nameable.
2832
- *
2833
- * An endpoint whose only `invoke` grant is the plugin's own `kay.agent` target is not reachable
2834
- * from Bonsai's surfaces (its pages and runtime clients), so an action the agent takes after the
2835
- * session's approval card cannot be taken around it.
2836
- */
2837
- /** Why an {@link KayAgentEndpoints.invoke} call produced no value. */
2838
- export declare type KayAgentEndpointFailureReason =
2839
- /** The manifest grants this plugin's `kay.agent` target no `invoke` on this endpoint. */
2840
- "not-declared"
2841
- /** The plugin's `kay.app` part is not running, or registered no handler for it. */
2842
- | "unavailable"
2843
- /** The handler did not answer within the host's fixed deadline (10 seconds). It may still finish. */
2844
- | "timed-out"
2845
- /** The caller's `signal` aborted. The handler may still finish. */
2846
- | "cancelled"
2847
- /** The handler threw; `message` is its error's message. */
2848
- | "failed"
2849
- /** The request or the handler's response does not match the endpoint's declared schema. */
2850
- | "invalid";
2851
-
2852
- export declare type KayAgentEndpointOutcome = {
2853
- readonly ok: true;
2854
- readonly value: unknown;
2855
- } | {
2856
- readonly ok: false;
2857
- readonly reason: KayAgentEndpointFailureReason;
2858
- readonly message: string;
2859
- };
2827
+ export declare type KayAgentEndpointFailureReason = PluginEndpointFailureReason;
2828
+
2829
+ export declare type KayAgentEndpointOutcome = PluginEndpointOutcome;
2860
2830
 
2861
- export declare interface KayAgentEndpoints {
2831
+ export declare interface KayAgentEndpoints extends PluginEndpointCaller {
2862
2832
  /**
2863
2833
  * Call `endpoint`, the local id this plugin's manifest declares on its `kay.app` target. Never
2864
2834
  * rejects: every failure is an outcome. Nothing is queued: when the app part is not running the
@@ -3132,10 +3102,9 @@ export declare interface KayAgentPluginApi {
3132
3102
  */
3133
3103
  readonly vendoredMcp: KayAgentVendoredMcp;
3134
3104
  /**
3135
- * Calls the endpoints this plugin's own `kay.app` part registered and the manifest grants this
3136
- * target `invoke` on, by local id. Never another plugin's. Every failure is an outcome, never a
3137
- * rejection; the host fixes a 10-second deadline. Always present; a host with no app part
3138
- * answers each call `unavailable`. See {@link KayAgentEndpoints} (SDK 0.17.3).
3105
+ * `invoke` calls this plugin's own declared app endpoint by local id. `invokePlugin` names a
3106
+ * provider plugin explicitly and checks this target's exact `endpoints.invoke` claim. Every
3107
+ * failure is an outcome; unavailable providers are never queued.
3139
3108
  */
3140
3109
  readonly endpoints: KayAgentEndpoints;
3141
3110
  /**
@@ -5128,6 +5097,16 @@ declare const PluginCapabilityRefusalV1: z.ZodObject<{
5128
5097
  delete: "delete";
5129
5098
  }>;
5130
5099
  }, z.core.$strict>;
5100
+ }, z.core.$strict>, z.ZodObject<{
5101
+ target: z.ZodEnum<{
5102
+ "kay.agent": "kay.agent";
5103
+ "kay.app": "kay.app";
5104
+ }>;
5105
+ slug: z.ZodLiteral<"endpoints.invoke">;
5106
+ envelope: z.ZodObject<{
5107
+ pluginId: z.ZodString;
5108
+ endpointId: z.ZodString;
5109
+ }, z.core.$strict>;
5131
5110
  }, z.core.$strict>, z.ZodObject<{
5132
5111
  target: z.ZodLiteral<"kay.app">;
5133
5112
  slug: z.ZodLiteral<"skills.read">;
@@ -5456,6 +5435,28 @@ export declare interface PluginDelegatedServiceEntry {
5456
5435
  readonly scheme: PluginDelegatedScheme;
5457
5436
  }
5458
5437
 
5438
+ /** Sessionless JSON calls to another plugin's declared, publicly reachable endpoint. */
5439
+ export declare interface PluginEndpointCaller {
5440
+ /**
5441
+ * Never rejects. Both payload and result are validated against the provider's declared schemas.
5442
+ * Nothing is queued or retried. Cancellation and timeouts leave the operation's effect unknown.
5443
+ */
5444
+ invokePlugin(providerPluginId: string, endpointLocalId: string, payload: unknown, options?: {
5445
+ readonly signal?: AbortSignal;
5446
+ }): Promise<PluginEndpointOutcome>;
5447
+ }
5448
+
5449
+ export declare type PluginEndpointFailureReason = "not-declared" | "unavailable" | "timed-out" | "cancelled" | "failed" | "invalid" | "denied";
5450
+
5451
+ export declare type PluginEndpointOutcome = {
5452
+ readonly ok: true;
5453
+ readonly value: unknown;
5454
+ } | {
5455
+ readonly ok: false;
5456
+ readonly reason: PluginEndpointFailureReason;
5457
+ readonly message: string;
5458
+ };
5459
+
5459
5460
  export declare const PluginEventEnvelope: z.ZodObject<{
5460
5461
  id: z.ZodString;
5461
5462
  localId: z.ZodString;
package/dist/kay-agent.js CHANGED
@@ -997,6 +997,13 @@ function createUnavailableUriCaller(message) {
997
997
  };
998
998
  }
999
999
 
1000
+ // packages/plugin-sdk/dist/endpoints.js
1001
+ function createUnavailablePluginEndpointCaller(message) {
1002
+ return {
1003
+ invokePlugin: async () => ({ ok: false, reason: "unavailable", message })
1004
+ };
1005
+ }
1006
+
1000
1007
  // packages/herd-uri-extensions/dist/limits.js
1001
1008
  var MAX_BYTES = 50 * 1024 * 1024;
1002
1009
  var MAX_OUTPUT_CHARS = 5e5;
@@ -1492,7 +1499,8 @@ function createUnavailableCompiler(message) {
1492
1499
  // packages/plugin-sdk/dist/kay-agent/endpoints.js
1493
1500
  function createUnavailableEndpoints(message) {
1494
1501
  return {
1495
- invoke: async () => ({ ok: false, reason: "unavailable", message })
1502
+ invoke: async () => ({ ok: false, reason: "unavailable", message }),
1503
+ ...createUnavailablePluginEndpointCaller(message)
1496
1504
  };
1497
1505
  }
1498
1506
 
@@ -1731,6 +1739,7 @@ export {
1731
1739
  createOsascriptRunner,
1732
1740
  createUnavailableCompiler,
1733
1741
  createUnavailableEndpoints,
1742
+ createUnavailablePluginEndpointCaller,
1734
1743
  createUnavailableUriCaller,
1735
1744
  declareProducedResources,
1736
1745
  defineAuthedTool,
package/dist/kay-app.d.ts CHANGED
@@ -952,6 +952,8 @@ export declare function createFallbackOnlySignals(): KayAppSignals;
952
952
  */
953
953
  export declare function createKayPluginLog(write: (line: KayPluginLogLine) => void, bound?: KayPluginLogAttributes): KayPluginLog;
954
954
 
955
+ export declare function createUnavailablePluginEndpointCaller(message: string): PluginEndpointCaller;
956
+
955
957
  /**
956
958
  * A `KayAppSealing` that answers `unavailable` to every call: what a host with no vault binds, so
957
959
  * `app.sealing` stays present on every host.
@@ -2900,8 +2902,11 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2900
2902
  * types; callers use the resource surface instead. Previously admitted SDK contracts are no
2901
2903
  * longer served because they included app.memory on notebook hosts. No compatibility alias
2902
2904
  * restores it; callers migrate and declare ^0.49.0.
2905
+ *
2906
+ * 0.50.0 adds explicit cross-plugin endpoint calls on both backend targets. The URI-only 0.49.0
2907
+ * contract remains served.
2903
2908
  */
2904
- declare const KAY_PLUGIN_SDK_VERSION: "0.49.0";
2909
+ declare const KAY_PLUGIN_SDK_VERSION: "0.50.0";
2905
2910
 
2906
2911
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2907
2912
 
@@ -4572,12 +4577,14 @@ export declare interface KayAppDynamicContextSearchOptions {
4572
4577
  export declare interface KayAppEndpointContext {
4573
4578
  readonly credentials: readonly KayAppResolvedCredential[];
4574
4579
  readonly signal: AbortSignal;
4580
+ /** Host-stamped origin of a sessionless cross-plugin call; absent for other callers. */
4581
+ readonly callerPluginId?: string;
4575
4582
  /** Record only a scheme from this call's credentials after its provider operation succeeds. */
4576
4583
  reportWorked(schemeId: string): void;
4577
4584
  }
4578
4585
 
4579
4586
  /** The app-wide endpoint bus; payloads and returned values must be JSON. */
4580
- export declare interface KayAppEndpoints {
4587
+ export declare interface KayAppEndpoints extends PluginEndpointCaller {
4581
4588
  register(name: string, handler: (payload: unknown, context: KayAppEndpointContext) => unknown | Promise<unknown>): void;
4582
4589
  }
4583
4590
 
@@ -5497,9 +5504,9 @@ export declare interface KayAppPluginApi {
5497
5504
  */
5498
5505
  readonly sealing: KayAppSealing;
5499
5506
  /**
5500
- * The app-wide endpoint bus (register handlers a consuming surface invokes). An endpoint whose
5501
- * only `invoke` grant is this plugin's own `kay.agent` target is reachable only from that target
5502
- * (`api.endpoints.invoke`), never from a surface.
5507
+ * Register this plugin's app handlers or call another plugin's declared endpoint with
5508
+ * `invokePlugin`. Foreign calls require this target's exact `endpoints.invoke` claim and
5509
+ * cannot reach an endpoint restricted to its owner's agent target.
5503
5510
  */
5504
5511
  readonly endpoints: KayAppEndpoints;
5505
5512
  /** Publish one event declared by this plugin's `kay.app` manifest target. */
@@ -9974,6 +9981,28 @@ declare type PluginCardSubmitResult<T> = {
9974
9981
  readonly ok: false;
9975
9982
  }>;
9976
9983
 
9984
+ /** Sessionless JSON calls to another plugin's declared, publicly reachable endpoint. */
9985
+ export declare interface PluginEndpointCaller {
9986
+ /**
9987
+ * Never rejects. Both payload and result are validated against the provider's declared schemas.
9988
+ * Nothing is queued or retried. Cancellation and timeouts leave the operation's effect unknown.
9989
+ */
9990
+ invokePlugin(providerPluginId: string, endpointLocalId: string, payload: unknown, options?: {
9991
+ readonly signal?: AbortSignal;
9992
+ }): Promise<PluginEndpointOutcome>;
9993
+ }
9994
+
9995
+ export declare type PluginEndpointFailureReason = "not-declared" | "unavailable" | "timed-out" | "cancelled" | "failed" | "invalid" | "denied";
9996
+
9997
+ export declare type PluginEndpointOutcome = {
9998
+ readonly ok: true;
9999
+ readonly value: unknown;
10000
+ } | {
10001
+ readonly ok: false;
10002
+ readonly reason: PluginEndpointFailureReason;
10003
+ readonly message: string;
10004
+ };
10005
+
9977
10006
  export declare const PluginEventEnvelope: z.ZodObject<{
9978
10007
  id: z.ZodString;
9979
10008
  localId: z.ZodString;
package/dist/kay-app.js CHANGED
@@ -308,6 +308,13 @@ function createUnavailableUriCaller(message) {
308
308
  };
309
309
  }
310
310
 
311
+ // packages/plugin-sdk/dist/endpoints.js
312
+ function createUnavailablePluginEndpointCaller(message) {
313
+ return {
314
+ invokePlugin: async () => ({ ok: false, reason: "unavailable", message })
315
+ };
316
+ }
317
+
311
318
  // packages/plugin-protocol/dist/plugin-signal-limits.js
312
319
  var PLUGIN_EVENT_REFUSED_ERROR_NAME = "PluginEventRefusedError";
313
320
  var PLUGIN_SIGNAL_KINDS = [
@@ -1106,6 +1113,7 @@ export {
1106
1113
  createConsoleKayPluginLog,
1107
1114
  createFallbackOnlySignals,
1108
1115
  createKayPluginLog,
1116
+ createUnavailablePluginEndpointCaller,
1109
1117
  createUnavailableSealing,
1110
1118
  createUnavailableSkills,
1111
1119
  createUnavailableTools,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaklabs-ai/plugin-sdk",
3
- "version": "0.49.0",
3
+ "version": "0.50.0",
4
4
  "description": "The Kay plugin SDK — types and helpers for authoring a Kay directory plugin.",
5
5
  "author": "YakLabs",
6
6
  "type": "module",
@@ -21,6 +21,10 @@
21
21
  "types": "./dist/uri.d.ts",
22
22
  "default": "./dist/uri.js"
23
23
  },
24
+ "./endpoints": {
25
+ "types": "./dist/endpoints.d.ts",
26
+ "default": "./dist/endpoints.js"
27
+ },
24
28
  "./kay-app/session-summary": {
25
29
  "types": "./dist/kay-app-session-summary.d.ts",
26
30
  "default": "./dist/kay-app-session-summary.js"