@yaklabs-ai/plugin-sdk 0.13.6 → 0.13.7
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 +19 -10
- package/THIRD-PARTY-INVENTORY.json +1 -1
- package/dist/agent-conversation.d.ts +93 -0
- package/dist/agent-conversation.js +174 -0
- package/dist/app-data.d.ts +7 -0
- package/dist/app-data.js +9 -0
- package/dist/kay-agent.d.ts +24 -0
- package/dist/transcript-review.d.ts +310 -0
- package/dist/transcript-review.js +680 -0
- package/dist/vendored-mcp.d.ts +1217 -0
- package/dist/vendored-mcp.js +471 -0
- package/package.json +17 -1
- package/skills/directory-plugin-authoring/SKILL.md +3 -2
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.13.
|
|
16
|
+
"@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.13.7"
|
|
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.13.
|
|
65
|
+
"compatibility": { "sdk": "^0.13.7" },
|
|
66
66
|
"targets": {
|
|
67
67
|
"kay": {
|
|
68
68
|
"agent": {
|
|
@@ -116,14 +116,23 @@ naming both versions, instead of loading it and finding no `activate`.
|
|
|
116
116
|
|
|
117
117
|
## Entrypoints
|
|
118
118
|
|
|
119
|
-
| Import
|
|
120
|
-
|
|
|
121
|
-
| `@bonsai/plugin-sdk/kay-agent`
|
|
122
|
-
| `@bonsai/plugin-sdk/kay-app`
|
|
123
|
-
| `@bonsai/plugin-sdk/kay-agent/testing`
|
|
124
|
-
| `@bonsai/plugin-sdk/disclosure`
|
|
125
|
-
| `@bonsai/plugin-sdk/time`
|
|
126
|
-
| `@bonsai/plugin-sdk/transcript`
|
|
119
|
+
| Import | What it gives you |
|
|
120
|
+
| --------------------------------------- | ------------------------------------------------------------------------------- |
|
|
121
|
+
| `@bonsai/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
|
|
122
|
+
| `@bonsai/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
|
|
123
|
+
| `@bonsai/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
|
|
124
|
+
| `@bonsai/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
|
|
125
|
+
| `@bonsai/plugin-sdk/time` | `Temporal` (Bonsai's own instance) and the time-zone helpers, from 0.13.6 |
|
|
126
|
+
| `@bonsai/plugin-sdk/transcript` | The active-branch walk; the turn walk and run records from 0.13.6 |
|
|
127
|
+
| `@bonsai/plugin-sdk/transcript-review` | The review fold: a session's spans, tool-call attempts and records, from 0.13.7 |
|
|
128
|
+
| `@bonsai/plugin-sdk/agent-conversation` | How a session's agent-to-agent traffic groups into conversations, from 0.13.7 |
|
|
129
|
+
| `@bonsai/plugin-sdk/app-data` | The app-data size caps, on an entry with no other import, from 0.13.7 |
|
|
130
|
+
| `@bonsai/plugin-sdk/vendored-mcp` | The kit for a plugin built on a vendor's hosted MCP server, from 0.13.7 |
|
|
131
|
+
|
|
132
|
+
A plugin that imports a subpath declares at least the version its row names (`^0.13.7` for the
|
|
133
|
+
last four). `vendored-mcp` builds the plugin's URI module (its link cards and help); hosting the
|
|
134
|
+
vendor's MCP server itself is a separate host decision, and Bonsai currently makes it only for
|
|
135
|
+
its own bundled plugins.
|
|
127
136
|
|
|
128
137
|
`kay-agent/host` is intentionally not published; it is Bonsai's own loading
|
|
129
138
|
machinery, not an authoring API.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** The admitted inbox receipt, not a target guessed from tool arguments or prose. */
|
|
2
|
+
export declare function admittedSendSessionId(details: unknown): string | undefined;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The admitted-spawn stamp, or `undefined` when nothing was started.
|
|
6
|
+
*
|
|
7
|
+
* Two generations of stamp exist in durable transcripts and both must parse
|
|
8
|
+
* forever: version 2 (the messaging contract) writes
|
|
9
|
+
* `{ version: 2, sessionId, displayName, backgroundTaskId }` and exists only
|
|
10
|
+
* for admitted spawns (rejections are tool errors and stamp nothing);
|
|
11
|
+
* version 1 wrote `{ version: 1, accepted, childSessionId, label, … }`, where
|
|
12
|
+
* `accepted: false` carries no child session.
|
|
13
|
+
*/
|
|
14
|
+
export declare function admittedSpawnSessionId(details: unknown): string | undefined;
|
|
15
|
+
|
|
16
|
+
export declare type AgentConversationBoundaryReason = "assistant_text" | "user" | "spawn" | "custom" | "surface" | "other";
|
|
17
|
+
|
|
18
|
+
export declare interface AgentConversationPeerGroup<TRef = unknown> {
|
|
19
|
+
readonly peerId: string;
|
|
20
|
+
readonly firstItemId: string;
|
|
21
|
+
readonly items: readonly AgentConversationSourceConversation<TRef>[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export declare type AgentConversationResultStatus = RunSettlementOutcome;
|
|
25
|
+
|
|
26
|
+
export declare interface AgentConversationRun<TRef = unknown> {
|
|
27
|
+
/** The first conversation item's id: stable while the run grows. */
|
|
28
|
+
readonly id: string;
|
|
29
|
+
/** Every conversation item, in canonical source order. */
|
|
30
|
+
readonly items: readonly AgentConversationSourceConversation<TRef>[];
|
|
31
|
+
/** Peers in first-appearance order. */
|
|
32
|
+
readonly peers: readonly AgentConversationPeerGroup<TRef>[];
|
|
33
|
+
/** Work strictly between two of this run's conversation items. */
|
|
34
|
+
readonly work: readonly AgentConversationRunWork[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Work a run can own: a tool attempt or a folded narration, in source order. */
|
|
38
|
+
declare type AgentConversationRunWork = AgentConversationSourceActivity | AgentConversationSourceNote;
|
|
39
|
+
|
|
40
|
+
declare interface AgentConversationSourceActivity {
|
|
41
|
+
readonly kind: "activity";
|
|
42
|
+
readonly attemptId: string;
|
|
43
|
+
readonly rowKey: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare interface AgentConversationSourceBoundary {
|
|
47
|
+
readonly kind: "boundary";
|
|
48
|
+
readonly id: string;
|
|
49
|
+
readonly reason: AgentConversationBoundaryReason;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export declare interface AgentConversationSourceConversation<TRef = unknown> {
|
|
53
|
+
readonly kind: "conversation";
|
|
54
|
+
/** Source identity: a tool attempt id (outbound) or message item id. */
|
|
55
|
+
readonly id: string;
|
|
56
|
+
readonly peerId: string;
|
|
57
|
+
readonly direction: "inbound" | "outbound" | "result";
|
|
58
|
+
readonly status?: AgentConversationResultStatus;
|
|
59
|
+
readonly rowKey: string;
|
|
60
|
+
readonly ref: TRef;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export declare type AgentConversationSourceItem<TRef = unknown> = AgentConversationSourceConversation<TRef> | AgentConversationRunWork | AgentConversationSourceBoundary;
|
|
64
|
+
|
|
65
|
+
/** Narration that paints only inside a folded "Did work" rail. */
|
|
66
|
+
declare interface AgentConversationSourceNote {
|
|
67
|
+
readonly kind: "note";
|
|
68
|
+
readonly id: string;
|
|
69
|
+
readonly rowKey: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export declare function groupAgentConversationStream<TRef>(stream: readonly AgentConversationSourceItem<TRef>[]): readonly AgentConversationRun<TRef>[];
|
|
73
|
+
|
|
74
|
+
export declare function immediateFollowingAgentConversationWave<TAttempt extends {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
}>(run: AgentConversationRun<unknown>, waves: readonly (readonly TAttempt[])[], stream: readonly AgentConversationSourceItem[], order: ReadonlyMap<string, number>, sources: ReadonlyMap<string, {
|
|
77
|
+
readonly rowKey: string;
|
|
78
|
+
}>, claimedWaveAttemptIds: ReadonlySet<string>): readonly TAttempt[] | undefined;
|
|
79
|
+
|
|
80
|
+
/** Whether a run changes today's rendering: a pair (2+ items with one peer) or 2+ peers. */
|
|
81
|
+
export declare function isFoldedAgentConversationRun(run: AgentConversationRun<unknown>): boolean;
|
|
82
|
+
|
|
83
|
+
/** The received metadata that both work ownership and the conversation renderer recognize. */
|
|
84
|
+
export declare function receivedConversation(customType: string | undefined, details: unknown): {
|
|
85
|
+
readonly peerId: string;
|
|
86
|
+
readonly direction: "inbound" | "result";
|
|
87
|
+
readonly status?: AgentConversationResultStatus;
|
|
88
|
+
} | undefined;
|
|
89
|
+
|
|
90
|
+
/** Terminal daemon-run outcomes shared by stored records and conversation results. */
|
|
91
|
+
declare type RunSettlementOutcome = "completed" | "interrupted" | "cancelled" | "failed";
|
|
92
|
+
|
|
93
|
+
export { }
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// packages/plugin-protocol/dist/agent-conversation.js
|
|
2
|
+
function workId(work) {
|
|
3
|
+
return work.kind === "activity" ? work.attemptId : work.id;
|
|
4
|
+
}
|
|
5
|
+
function freezeRun(run) {
|
|
6
|
+
const peers = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const item of run.items) {
|
|
8
|
+
const items = peers.get(item.peerId);
|
|
9
|
+
if (items === void 0)
|
|
10
|
+
peers.set(item.peerId, [item]);
|
|
11
|
+
else
|
|
12
|
+
items.push(item);
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
id: run.items[0].id,
|
|
16
|
+
items: run.items,
|
|
17
|
+
peers: [...peers].map(([peerId, items]) => ({
|
|
18
|
+
peerId,
|
|
19
|
+
firstItemId: items[0].id,
|
|
20
|
+
items
|
|
21
|
+
})),
|
|
22
|
+
work: run.work
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function groupAgentConversationStream(stream) {
|
|
26
|
+
const runs = [];
|
|
27
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
28
|
+
let active;
|
|
29
|
+
let queued = [];
|
|
30
|
+
const close = () => {
|
|
31
|
+
if (active !== void 0)
|
|
32
|
+
runs.push(freezeRun(active));
|
|
33
|
+
active = void 0;
|
|
34
|
+
queued = [];
|
|
35
|
+
};
|
|
36
|
+
for (const item of stream) {
|
|
37
|
+
if (item.kind === "boundary") {
|
|
38
|
+
close();
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (item.kind === "activity" || item.kind === "note") {
|
|
42
|
+
if (active !== void 0)
|
|
43
|
+
queued.push(item);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (active === void 0) {
|
|
47
|
+
active = { items: [item], work: [] };
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
for (const work of queued) {
|
|
51
|
+
if (claimed.has(workId(work)))
|
|
52
|
+
continue;
|
|
53
|
+
claimed.add(workId(work));
|
|
54
|
+
active.work.push(work);
|
|
55
|
+
}
|
|
56
|
+
queued = [];
|
|
57
|
+
active.items.push(item);
|
|
58
|
+
}
|
|
59
|
+
close();
|
|
60
|
+
return runs;
|
|
61
|
+
}
|
|
62
|
+
function immediateFollowingAgentConversationWave(run, waves, stream, order, sources, claimedWaveAttemptIds) {
|
|
63
|
+
if (run.work.length === 0)
|
|
64
|
+
return void 0;
|
|
65
|
+
const runIds = new Set(run.items.map((item) => item.id));
|
|
66
|
+
const end = Math.max(...run.items.map((item) => order.get(item.id) ?? -Infinity));
|
|
67
|
+
if (!Number.isFinite(end))
|
|
68
|
+
return void 0;
|
|
69
|
+
let candidate;
|
|
70
|
+
let candidateStart = Infinity;
|
|
71
|
+
for (const wave of waves) {
|
|
72
|
+
const followingAttempts = wave.filter((attempt) => {
|
|
73
|
+
const position = order.get(attempt.id);
|
|
74
|
+
return position !== void 0 && position > end && !claimedWaveAttemptIds.has(attempt.id);
|
|
75
|
+
});
|
|
76
|
+
if (followingAttempts.length === 0)
|
|
77
|
+
continue;
|
|
78
|
+
if (followingAttempts.some((attempt) => sources.get(attempt.id)?.rowKey !== run.items.at(-1)?.rowKey))
|
|
79
|
+
continue;
|
|
80
|
+
const start = Math.min(...followingAttempts.map((attempt) => order.get(attempt.id) ?? Infinity));
|
|
81
|
+
if (start < candidateStart) {
|
|
82
|
+
candidate = followingAttempts;
|
|
83
|
+
candidateStart = start;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (candidate === void 0)
|
|
87
|
+
return void 0;
|
|
88
|
+
const waveIds = new Set(candidate.map((attempt) => attempt.id));
|
|
89
|
+
for (const item of stream) {
|
|
90
|
+
const position = order.get(item.kind === "activity" ? item.attemptId : item.id);
|
|
91
|
+
if (position === void 0 || position <= end || position >= candidateStart)
|
|
92
|
+
continue;
|
|
93
|
+
if (item.kind === "conversation" && !runIds.has(item.id))
|
|
94
|
+
return void 0;
|
|
95
|
+
if (item.kind !== "activity" && item.kind !== "conversation")
|
|
96
|
+
return void 0;
|
|
97
|
+
if (item.kind === "activity" && !waveIds.has(item.attemptId))
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
return candidate;
|
|
101
|
+
}
|
|
102
|
+
function isFoldedAgentConversationRun(run) {
|
|
103
|
+
return run.peers.length >= 2 || run.peers.some((peer) => peer.items.length >= 2);
|
|
104
|
+
}
|
|
105
|
+
function admittedSpawnSessionId(details) {
|
|
106
|
+
if (typeof details !== "object" || details === null)
|
|
107
|
+
return void 0;
|
|
108
|
+
const record = details;
|
|
109
|
+
const sessionId = typeof record["sessionId"] === "string" ? record["sessionId"] : record["accepted"] === true && typeof record["childSessionId"] === "string" ? record["childSessionId"] : void 0;
|
|
110
|
+
return sessionId === void 0 || sessionId.trim() === "" ? void 0 : sessionId.trim();
|
|
111
|
+
}
|
|
112
|
+
function admittedSendSessionId(details) {
|
|
113
|
+
if (typeof details !== "object" || details === null)
|
|
114
|
+
return void 0;
|
|
115
|
+
const record = details;
|
|
116
|
+
const sessionId = typeof record["sessionId"] === "string" ? record["sessionId"].trim() : "";
|
|
117
|
+
return sessionId && typeof record["rowId"] === "string" && record["rowId"] !== "" && typeof record["backgroundTaskId"] === "string" ? sessionId : void 0;
|
|
118
|
+
}
|
|
119
|
+
function receivedConversation(customType, details) {
|
|
120
|
+
if (typeof details !== "object" || details === null)
|
|
121
|
+
return void 0;
|
|
122
|
+
const record = details;
|
|
123
|
+
if (customType === "collaboration_message") {
|
|
124
|
+
const provenance2 = record["provenance"];
|
|
125
|
+
if (typeof record["senderSessionId"] !== "string" || record["kind"] !== "message" && record["kind"] !== "progress" || typeof provenance2 !== "object" || provenance2 === null)
|
|
126
|
+
return void 0;
|
|
127
|
+
const source = provenance2;
|
|
128
|
+
if (source["source"] !== "subagent" || typeof source["sourceId"] !== "string")
|
|
129
|
+
return void 0;
|
|
130
|
+
return { peerId: record["senderSessionId"], direction: "inbound" };
|
|
131
|
+
}
|
|
132
|
+
if (customType !== "subagent_result")
|
|
133
|
+
return void 0;
|
|
134
|
+
const provenance = subagentProvenanceOf(record);
|
|
135
|
+
const status = record["status"];
|
|
136
|
+
if (provenance === void 0 || provenance.sourceId === "" || status !== "completed" && status !== "failed" && status !== "cancelled" && status !== "interrupted")
|
|
137
|
+
return void 0;
|
|
138
|
+
return { peerId: provenance.sourceId, direction: "result", status };
|
|
139
|
+
}
|
|
140
|
+
function subagentProvenanceOf(record) {
|
|
141
|
+
const provenance = record["provenance"];
|
|
142
|
+
if (typeof provenance === "object" && provenance !== null) {
|
|
143
|
+
const p = provenance;
|
|
144
|
+
if (p["source"] === "subagent" && typeof p["sourceId"] === "string") {
|
|
145
|
+
const label = p["label"];
|
|
146
|
+
return {
|
|
147
|
+
source: "subagent",
|
|
148
|
+
sourceId: p["sourceId"],
|
|
149
|
+
...typeof label === "string" ? { label } : {}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const attribution = record["attribution"];
|
|
154
|
+
if (typeof attribution === "object" && attribution !== null) {
|
|
155
|
+
const a = attribution;
|
|
156
|
+
if (a["kind"] === "subagent" && typeof a["childSessionId"] === "string") {
|
|
157
|
+
const label = a["label"];
|
|
158
|
+
return {
|
|
159
|
+
source: "subagent",
|
|
160
|
+
sourceId: a["childSessionId"],
|
|
161
|
+
...typeof label === "string" ? { label } : {}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
export {
|
|
168
|
+
admittedSendSessionId,
|
|
169
|
+
admittedSpawnSessionId,
|
|
170
|
+
groupAgentConversationStream,
|
|
171
|
+
immediateFollowingAgentConversationWave,
|
|
172
|
+
isFoldedAgentConversationRun,
|
|
173
|
+
receivedConversation
|
|
174
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Maximum UTF-8 JSON size of one plugin app-data live change. */
|
|
2
|
+
export declare const KAY_APP_DATA_CHANGE_MAX_BYTES: number;
|
|
3
|
+
|
|
4
|
+
/** Maximum UTF-8 JSON size of one plugin app-data snapshot. */
|
|
5
|
+
export declare const KAY_APP_DATA_SNAPSHOT_MAX_BYTES: number;
|
|
6
|
+
|
|
7
|
+
export { }
|
package/dist/app-data.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// packages/plugin-protocol/dist/app-data.js
|
|
2
|
+
var KAY_APP_DATA_SNAPSHOT_MAX_BYTES = 16 * 1024 * 1024;
|
|
3
|
+
var KAY_APP_DATA_CHANGE_MAX_BYTES = 256 * 1024;
|
|
4
|
+
var KAY_APP_DATA_READ_REQUEST_MAX_BYTES = 64 * 1024;
|
|
5
|
+
var KAY_APP_DATA_READ_RESULT_MAX_BYTES = 16 * 1024 * 1024;
|
|
6
|
+
export {
|
|
7
|
+
KAY_APP_DATA_CHANGE_MAX_BYTES,
|
|
8
|
+
KAY_APP_DATA_SNAPSHOT_MAX_BYTES
|
|
9
|
+
};
|
package/dist/kay-agent.d.ts
CHANGED
|
@@ -4919,6 +4919,30 @@ declare const PluginCapabilityRefusalV1: z.ZodObject<{
|
|
|
4919
4919
|
envelope: z.ZodObject<{
|
|
4920
4920
|
binary: z.ZodString;
|
|
4921
4921
|
}, z.core.$strict>;
|
|
4922
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
4923
|
+
target: z.ZodLiteral<"plugin">;
|
|
4924
|
+
slug: z.ZodLiteral<"mcp.host-server">;
|
|
4925
|
+
envelope: z.ZodObject<{
|
|
4926
|
+
name: z.ZodString;
|
|
4927
|
+
url: z.ZodString;
|
|
4928
|
+
}, z.core.$strict>;
|
|
4929
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
4930
|
+
target: z.ZodLiteral<"plugin">;
|
|
4931
|
+
slug: z.ZodLiteral<"prompt.resident">;
|
|
4932
|
+
envelope: z.ZodObject<{}, z.core.$strict>;
|
|
4933
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
4934
|
+
target: z.ZodLiteral<"plugin">;
|
|
4935
|
+
slug: z.ZodLiteral<"skills.declared-source">;
|
|
4936
|
+
envelope: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4937
|
+
channel: z.ZodLiteral<"git-clone">;
|
|
4938
|
+
locator: z.ZodString;
|
|
4939
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
4940
|
+
subdir: z.ZodOptional<z.ZodString>;
|
|
4941
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
4942
|
+
channel: z.ZodLiteral<"installer">;
|
|
4943
|
+
command: z.ZodString;
|
|
4944
|
+
args: z.ZodArray<z.ZodString>;
|
|
4945
|
+
}, z.core.$strict>], "channel">;
|
|
4922
4946
|
}, z.core.$strict>, z.ZodObject<{
|
|
4923
4947
|
target: z.ZodEnum<{
|
|
4924
4948
|
"kay.agent": "kay.agent";
|