@frockbot/applet-sdk 0.7.111 → 0.7.113
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 +7 -2
- package/package.json +1 -1
- package/plugin/index.d.ts +134 -0
- package/src/build/plugin.ts +18 -0
package/README.md
CHANGED
|
@@ -44,9 +44,14 @@ which `applet_create` writes through the Workspace.
|
|
|
44
44
|
|
|
45
45
|
A Plugin (ADR 0026) is written against `@frockbot/applet-sdk/plugin`, which
|
|
46
46
|
is declarations only: `plugin.ts` exports `tools` and `execute`, and may
|
|
47
|
-
export `hooks`, `services`, `triggers` and `
|
|
47
|
+
export `hooks`, `services`, `triggers`, `views` and `modelProviders`, beside a `plugin.json` descriptor.
|
|
48
48
|
`tools` may be empty — a Plugin that only serves hooks is admissible, because
|
|
49
|
-
the kernel's own descriptor contract admits one.
|
|
49
|
+
the kernel's own descriptor contract admits one. A model provider
|
|
50
|
+
(`PluginModelProvider`, ADR 0032) answers a normalized model request with
|
|
51
|
+
normalized stream events and makes its one upstream call through
|
|
52
|
+
`ctx.modelTransport`; the deployment serves it only from the artifact its own
|
|
53
|
+
provider catalog names, so this is not a way for a Bot-written Plugin to reach
|
|
54
|
+
a provider.
|
|
50
55
|
`runPluginBuildV1(directory, { mode, id })` is four stages — `descriptor`,
|
|
51
56
|
`typecheck`, `bundle`, `describe` — with no lint stage, because a Plugin's
|
|
52
57
|
reach is a grant the descriptor declares and the kernel enforces. The bundle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/applet-sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.113",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Authoring SDK for FrockBot Applets: schema-first Durable Object server, TanStack DB client, component kit, linter, and the build pipeline.",
|
package/plugin/index.d.ts
CHANGED
|
@@ -157,6 +157,129 @@ export interface PluginModel {
|
|
|
157
157
|
>;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
/** One message in the normalized request a model provider is handed. */
|
|
161
|
+
export interface PluginModelMessage {
|
|
162
|
+
role: "user" | "assistant" | "tool";
|
|
163
|
+
[key: string]: unknown;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* One model request, normalized by the kernel: the same shape a Package's
|
|
168
|
+
* provider receives, minus the Connection the host holds on the Plugin's
|
|
169
|
+
* behalf.
|
|
170
|
+
*/
|
|
171
|
+
export interface PluginModelRequest {
|
|
172
|
+
requestId: string;
|
|
173
|
+
provider: string;
|
|
174
|
+
model: string;
|
|
175
|
+
system: string;
|
|
176
|
+
messages: PluginModelMessage[];
|
|
177
|
+
tools: { name: string; description: string; inputSchema: JsonSchema }[];
|
|
178
|
+
responseFormat?: { type: string; [key: string]: unknown };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* One normalized stream event a provider answers with. The kernel decodes
|
|
183
|
+
* every field strictly, so a provider that invents an event fails its call
|
|
184
|
+
* rather than half-rendering a reply.
|
|
185
|
+
*/
|
|
186
|
+
export type PluginModelStreamEvent =
|
|
187
|
+
| {
|
|
188
|
+
type: "provider-state";
|
|
189
|
+
/** Opaque provider content the kernel replays on later turns. */
|
|
190
|
+
state: { [key: string]: unknown };
|
|
191
|
+
}
|
|
192
|
+
| { type: "text-delta"; text: string }
|
|
193
|
+
| {
|
|
194
|
+
/**
|
|
195
|
+
* A heartbeat: real upstream bytes that are not the reply — a reasoning
|
|
196
|
+
* model thinking, arguments still arriving. It reaches no one and shows
|
|
197
|
+
* nothing; it is how a long stretch with no visible output is told
|
|
198
|
+
* apart from a dead socket.
|
|
199
|
+
*/
|
|
200
|
+
type: "progress";
|
|
201
|
+
}
|
|
202
|
+
| { type: "tool-call"; call: { id: string; name: string; input: unknown } }
|
|
203
|
+
| {
|
|
204
|
+
type: "usage";
|
|
205
|
+
usage: {
|
|
206
|
+
inputTokens: number;
|
|
207
|
+
outputTokens: number;
|
|
208
|
+
cachedInputTokens?: number;
|
|
209
|
+
reasoningTokens?: number;
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
| { type: "response-format-note"; note: { [key: string]: unknown } }
|
|
213
|
+
| { type: "structured-output-failure"; failure: { [key: string]: unknown } }
|
|
214
|
+
| { type: "finish"; reason: "completed" | "tool-calls" | "max-tokens" }
|
|
215
|
+
| {
|
|
216
|
+
/**
|
|
217
|
+
* The provider refused, in the Plugin's own words. The classification
|
|
218
|
+
* tells the kernel's retry policy what to do: `permanent` is not
|
|
219
|
+
* retried, `transient` is, and `unknown` takes the kernel's default.
|
|
220
|
+
*/
|
|
221
|
+
type: "provider-failure";
|
|
222
|
+
classification: "transient" | "permanent" | "unknown";
|
|
223
|
+
reason: string;
|
|
224
|
+
retryAfterMs?: number;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/** What the host transport answers with. */
|
|
228
|
+
export type PluginModelTransportOutcome =
|
|
229
|
+
| {
|
|
230
|
+
status: "streaming";
|
|
231
|
+
httpStatus: number;
|
|
232
|
+
/** The provider's body, streamed. Decode it as the provider frames it. */
|
|
233
|
+
body: ReadableStream<Uint8Array>;
|
|
234
|
+
}
|
|
235
|
+
| {
|
|
236
|
+
status: "refused";
|
|
237
|
+
httpStatus: number;
|
|
238
|
+
/** The host's own words; an upstream error body is never forwarded. */
|
|
239
|
+
reason: string;
|
|
240
|
+
retryAfterMs?: number;
|
|
241
|
+
}
|
|
242
|
+
| { status: "unavailable"; reason: string };
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The model transport a provider contribution may call, exactly once per
|
|
246
|
+
* model call. The host resolves the Connection, sends to the one endpoint and
|
|
247
|
+
* route the deployment serves the provider on, attaches the credential
|
|
248
|
+
* server-side and streams the provider's bytes back. A Plugin never sees the
|
|
249
|
+
* credential, cannot name a Connection or a destination, and cannot follow a
|
|
250
|
+
* redirect.
|
|
251
|
+
*/
|
|
252
|
+
export type PluginModelTransport = (request: {
|
|
253
|
+
/** The request body, exactly as the upstream should receive it. */
|
|
254
|
+
body: string;
|
|
255
|
+
}) => Promise<PluginModelTransportOutcome>;
|
|
256
|
+
|
|
257
|
+
/** `ctx` inside one model call served by this Plugin's provider contribution. */
|
|
258
|
+
export interface PluginModelContext extends PluginContext {
|
|
259
|
+
/** This call's one credentialed upstream call. */
|
|
260
|
+
readonly modelTransport: PluginModelTransport;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* One model provider a Plugin serves (ADR 0032). The `id` is the provider
|
|
265
|
+
* type a Bot's model selection names; the descriptor declares it too, with
|
|
266
|
+
* the protocol version, the credential scheme and the endpoint the host
|
|
267
|
+
* attaches them to, and the two are checked against each other at mount.
|
|
268
|
+
*/
|
|
269
|
+
export interface PluginModelProvider {
|
|
270
|
+
/**
|
|
271
|
+
* One model call: the kernel hands a normalized request and the Plugin
|
|
272
|
+
* answers with normalized events, reached through `ctx.modelTransport`.
|
|
273
|
+
*/
|
|
274
|
+
stream(
|
|
275
|
+
request: PluginModelRequest,
|
|
276
|
+
ctx: PluginModelContext,
|
|
277
|
+
): AsyncIterable<PluginModelStreamEvent>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Every model provider the module serves, by provider id. */
|
|
281
|
+
export type PluginModelProviders = Record<string, PluginModelProvider>;
|
|
282
|
+
|
|
160
283
|
export type MemoryScope = "bot" | "user" | "project";
|
|
161
284
|
export type MemoryTier = "profile" | "log" | "note";
|
|
162
285
|
|
|
@@ -253,6 +376,11 @@ export interface PluginContext {
|
|
|
253
376
|
readonly settings: PluginSettings;
|
|
254
377
|
/** The `ai` grant. */
|
|
255
378
|
readonly model?: PluginModel;
|
|
379
|
+
/**
|
|
380
|
+
* The credentialed transport, present exactly while this Plugin is serving
|
|
381
|
+
* one of its model provider contributions. A tool call's `ctx` has none.
|
|
382
|
+
*/
|
|
383
|
+
readonly modelTransport?: PluginModelTransport;
|
|
256
384
|
/** The `memory` grant. */
|
|
257
385
|
readonly memory?: PluginMemory;
|
|
258
386
|
/** The `workspace` grant. */
|
|
@@ -611,4 +739,10 @@ export interface PluginModule {
|
|
|
611
739
|
* the card's `dataSchema` and `render` answers with the surface.
|
|
612
740
|
*/
|
|
613
741
|
cards?: Record<string, PluginCard>;
|
|
742
|
+
/**
|
|
743
|
+
* One entry per model provider declared under `modelProviders` in
|
|
744
|
+
* `plugin.json` (ADR 0032). A Bot that selects that provider runs this
|
|
745
|
+
* contribution; the host serves the credential through `ctx.modelTransport`.
|
|
746
|
+
*/
|
|
747
|
+
modelProviders?: PluginModelProviders;
|
|
614
748
|
}
|
package/src/build/plugin.ts
CHANGED
|
@@ -54,6 +54,8 @@ export interface PluginDescriptionV1 {
|
|
|
54
54
|
views: string[];
|
|
55
55
|
/** The cards the module draws, by id (ADR 0030). */
|
|
56
56
|
cards: string[];
|
|
57
|
+
/** The model providers the module serves, by provider id (ADR 0032). */
|
|
58
|
+
modelProviders: string[];
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export interface PluginBuildManifestV1 extends PluginDescriptionV1 {
|
|
@@ -279,6 +281,20 @@ function names(value, label) {
|
|
|
279
281
|
});
|
|
280
282
|
}
|
|
281
283
|
|
|
284
|
+
function modelProviderNames(value) {
|
|
285
|
+
if (value === undefined) return [];
|
|
286
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
287
|
+
throw new Error('"modelProviders" must be an object');
|
|
288
|
+
}
|
|
289
|
+
return Object.keys(value).map(function (providerId) {
|
|
290
|
+
var provider = value[providerId];
|
|
291
|
+
if (!provider || typeof provider !== "object" || typeof provider.stream !== "function") {
|
|
292
|
+
throw new Error('model provider "' + providerId + '" must export a stream function');
|
|
293
|
+
}
|
|
294
|
+
return providerId;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
282
298
|
function cardNames(value) {
|
|
283
299
|
if (value === undefined) return [];
|
|
284
300
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -320,6 +336,7 @@ function describe() {
|
|
|
320
336
|
triggers: names(plugin.triggers, "triggers"),
|
|
321
337
|
views: names(plugin.views, "views"),
|
|
322
338
|
cards: cardNames(plugin.cards),
|
|
339
|
+
modelProviders: modelProviderNames(plugin.modelProviders),
|
|
323
340
|
};
|
|
324
341
|
}
|
|
325
342
|
|
|
@@ -414,6 +431,7 @@ function validateDescription(input: PluginDescriptionV1): PluginDescriptionV1 {
|
|
|
414
431
|
triggers: [...input.triggers],
|
|
415
432
|
views: [...input.views],
|
|
416
433
|
cards: [...(input.cards ?? [])],
|
|
434
|
+
modelProviders: [...(input.modelProviders ?? [])],
|
|
417
435
|
};
|
|
418
436
|
}
|
|
419
437
|
|