@frockbot/plugin-subagents 0.1.3 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frockbot/plugin-subagents",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -27,8 +27,8 @@
27
27
  "typecheck": "tsc --noEmit -p tsconfig.json"
28
28
  },
29
29
  "dependencies": {
30
- "@frockbot/kernel-agent-loop": "0.1.3",
31
- "@frockbot/kernel-contracts": "0.1.3",
30
+ "@frockbot/kernel-agent-loop": "0.1.4",
31
+ "@frockbot/kernel-contracts": "0.1.4",
32
32
  "cordis": "4.0.0-rc.8"
33
33
  },
34
34
  "devDependencies": {
package/src/agent.test.ts CHANGED
@@ -23,7 +23,6 @@ import {
23
23
  import type { ToolExecutionContext } from "@frockbot/kernel-contracts";
24
24
 
25
25
  const BINDING: TaskModelBindingV1 = {
26
- assignmentId: "asg-1",
27
26
  packageId: "provider-ollama-cloud",
28
27
  capabilityId: "ollama-cloud-models",
29
28
  connectionId: "conn-1",
@@ -55,7 +54,7 @@ function tool(
55
54
  turnType,
56
55
  models: () =>
57
56
  subagentModelCatalogV1({
58
- assignments: [BINDING],
57
+ bindings: [BINDING],
59
58
  defaultBinding: BINDING,
60
59
  turnType,
61
60
  }),
@@ -194,7 +193,7 @@ describe("the <available_subagent_models> section", () => {
194
193
  const section = createSubagentModelsPromptSectionV1({
195
194
  models: () =>
196
195
  subagentModelCatalogV1({
197
- assignments: [BINDING],
196
+ bindings: [BINDING],
198
197
  defaultBinding: BINDING,
199
198
  turnType: "chat",
200
199
  }),
@@ -210,7 +209,7 @@ describe("the <available_subagent_models> section", () => {
210
209
  );
211
210
  });
212
211
 
213
- test("renders nothing for a Bot with no enabled model Assignment", async () => {
212
+ test("renders nothing for a Bot with no enabled model binding", async () => {
214
213
  const section = createSubagentModelsPromptSectionV1({ models: () => [] });
215
214
  expect(
216
215
  await section.render({
package/src/agent.ts CHANGED
@@ -244,7 +244,7 @@ export interface SubagentsRuntimeHostV1 {
244
244
  * into each step of its Turn and folds what it gets into that step's inputs.
245
245
  */
246
246
  drainMessages?(): Promise<readonly PendingTaskMessageV1[]>;
247
- /** The models this Turn may dispatch onto, resolved from enabled Assignments. */
247
+ /** The models this Turn may dispatch onto, resolved from enabled bindings. */
248
248
  models(): readonly SubagentModelOptionV1[];
249
249
  dispatch(
250
250
  request: SubagentDispatchRequestV1,
@@ -7,23 +7,22 @@ import {
7
7
  } from "./models.js";
8
8
  import type { TaskModelBindingV1 } from "./records.js";
9
9
 
10
- function assignment(
10
+ function binding(
11
11
  packageId: string,
12
12
  providerModelId: string,
13
- assignmentId = `asg-${providerModelId}`,
13
+ connectionId = `conn-${providerModelId}`,
14
14
  ): TaskModelBindingV1 {
15
15
  return {
16
- assignmentId,
17
16
  packageId,
18
17
  capabilityId: `${packageId}-models`,
19
- connectionId: `conn-${assignmentId}`,
18
+ connectionId,
20
19
  provider: packageId,
21
20
  providerModelId,
22
21
  };
23
22
  }
24
23
 
25
- const DEFAULT = assignment("provider-ollama-cloud", "glm-5.3-flash:cloud");
26
- const SECOND = assignment("provider-foundation", "sand-automation");
24
+ const DEFAULT = binding("provider-ollama-cloud", "glm-5.3-flash:cloud");
25
+ const SECOND = binding("provider-foundation", "sand-automation");
27
26
 
28
27
  describe("the slug", () => {
29
28
  test("is the Package and the provider model, and nothing else", () => {
@@ -34,9 +33,9 @@ describe("the slug", () => {
34
33
  });
35
34
 
36
35
  describe("the catalog one Turn is offered", () => {
37
- test("is built from the Bot's enabled model Assignments, default first", () => {
36
+ test("is built from the User's enabled model bindings, default first", () => {
38
37
  const catalog = subagentModelCatalogV1({
39
- assignments: [SECOND, DEFAULT],
38
+ bindings: [SECOND, DEFAULT],
40
39
  defaultBinding: DEFAULT,
41
40
  turnType: "chat",
42
41
  });
@@ -48,15 +47,15 @@ describe("the catalog one Turn is offered", () => {
48
47
  expect(catalog[1]?.isDefault).toBe(false);
49
48
  });
50
49
 
51
- test("keeps one entry per slug when two Assignments name one model", () => {
52
- const twin = assignment(
50
+ test("keeps one entry per slug when two bindings name one model", () => {
51
+ const twin = binding(
53
52
  "provider-ollama-cloud",
54
53
  "glm-5.3-flash:cloud",
55
54
  "asg-twin",
56
55
  );
57
56
  expect(
58
57
  subagentModelCatalogV1({
59
- assignments: [DEFAULT, twin],
58
+ bindings: [DEFAULT, twin],
60
59
  defaultBinding: DEFAULT,
61
60
  turnType: "chat",
62
61
  }),
@@ -66,7 +65,7 @@ describe("the catalog one Turn is offered", () => {
66
65
  test("renders exactly one slug on an automation turn — the Bot's own binding", () => {
67
66
  for (const turnType of ["automation", "subagent"] as const) {
68
67
  const catalog = subagentModelCatalogV1({
69
- assignments: [SECOND, DEFAULT],
68
+ bindings: [SECOND, DEFAULT],
70
69
  defaultBinding: DEFAULT,
71
70
  turnType,
72
71
  });
@@ -76,16 +75,16 @@ describe("the catalog one Turn is offered", () => {
76
75
  }
77
76
  });
78
77
 
79
- test("is empty for a Bot with no enabled model Assignment", () => {
80
- expect(
81
- subagentModelCatalogV1({ assignments: [], turnType: "chat" }),
82
- ).toEqual([]);
78
+ test("is empty for a Bot with no enabled model binding", () => {
79
+ expect(subagentModelCatalogV1({ bindings: [], turnType: "chat" })).toEqual(
80
+ [],
81
+ );
83
82
  });
84
83
  });
85
84
 
86
85
  describe("resolving a `Task` model against the catalog", () => {
87
86
  const catalog = subagentModelCatalogV1({
88
- assignments: [SECOND, DEFAULT],
87
+ bindings: [SECOND, DEFAULT],
89
88
  defaultBinding: DEFAULT,
90
89
  turnType: "chat",
91
90
  });
@@ -98,14 +97,14 @@ describe("resolving a `Task` model against the catalog", () => {
98
97
  });
99
98
  });
100
99
 
101
- test("a named slug resolves to the Assignment that carries it", () => {
100
+ test("a named slug resolves to the binding that carries it", () => {
102
101
  const resolved = resolveSubagentModelV1(
103
102
  catalog,
104
103
  "provider-foundation/sand-automation",
105
104
  );
106
105
  expect(resolved).toMatchObject({
107
106
  status: "resolved",
108
- model: { binding: { assignmentId: SECOND.assignmentId } },
107
+ model: { binding: { connectionId: SECOND.connectionId } },
109
108
  });
110
109
  });
111
110
 
@@ -119,7 +118,7 @@ describe("resolving a `Task` model against the catalog", () => {
119
118
 
120
119
  test("an automation turn refuses the second slug it was not shown", () => {
121
120
  const narrowed = subagentModelCatalogV1({
122
- assignments: [SECOND, DEFAULT],
121
+ bindings: [SECOND, DEFAULT],
123
122
  defaultBinding: DEFAULT,
124
123
  turnType: "automation",
125
124
  });
@@ -128,7 +127,7 @@ describe("resolving a `Task` model against the catalog", () => {
128
127
  ).toMatchObject({ status: "refused" });
129
128
  });
130
129
 
131
- test("a Bot with no model Assignment is refused rather than defaulted", () => {
130
+ test("a Bot with no model binding is refused rather than defaulted", () => {
132
131
  expect(resolveSubagentModelV1([], undefined)).toMatchObject({
133
132
  status: "refused",
134
133
  });
@@ -142,7 +141,7 @@ describe("<available_subagent_models>", () => {
142
141
  test("renders one element per slug and marks the default", () => {
143
142
  const rendered = renderAvailableSubagentModelsPromptV1(
144
143
  subagentModelCatalogV1({
145
- assignments: [SECOND, DEFAULT],
144
+ bindings: [SECOND, DEFAULT],
146
145
  defaultBinding: DEFAULT,
147
146
  turnType: "chat",
148
147
  }),
@@ -159,7 +158,7 @@ describe("<available_subagent_models>", () => {
159
158
  test("renders exactly one model line on an automation turn", () => {
160
159
  const rendered = renderAvailableSubagentModelsPromptV1(
161
160
  subagentModelCatalogV1({
162
- assignments: [SECOND, DEFAULT],
161
+ bindings: [SECOND, DEFAULT],
163
162
  defaultBinding: DEFAULT,
164
163
  turnType: "automation",
165
164
  }),
package/src/models.ts CHANGED
@@ -7,8 +7,8 @@
7
7
  // default binding, GrokBot's `sand-automation` — and an omitted `model`
8
8
  // inherits the parent's binding rather than picking anything.
9
9
  //
10
- // A slug is `<packageId>/<providerModelId>`. It names an *Assignment*, not a
11
- // provider: resolution runs against the Bot's enabled model Assignments, so a
10
+ // A slug is `<packageId>/<providerModelId>`. It names an enabled binding, not a
11
+ // provider: resolution runs against the User's enabled model Capabilities, so a
12
12
  // slug the Bot invents resolves to nothing and the dispatch is refused.
13
13
 
14
14
  import type { TurnTypeV1 } from "@frockbot/kernel-contracts";
@@ -22,7 +22,7 @@ import {
22
22
  /** Most slugs the prompt section will ever render. A catalog, not a directory. */
23
23
  export const SUBAGENT_MODEL_CATALOG_LIMIT_V1 = 32;
24
24
 
25
- /** One offerable model, projected from one enabled model Assignment. */
25
+ /** One offerable model, projected from one enabled model binding. */
26
26
  export interface SubagentModelOptionV1 {
27
27
  slug: string;
28
28
  binding: TaskModelBindingV1;
@@ -41,7 +41,7 @@ export function subagentModelSlugV1(binding: {
41
41
  * The turn types that may see more than one slug.
42
42
  *
43
43
  * An `automation` or `subagent` turn renders exactly one — the Bot's default
44
- * binding. It is not a permission (the Assignments are the same either way); it
44
+ * binding. It is not a permission (the enabled set is the same either way); it
45
45
  * is that an unattended Turn choosing a model per task is a decision with
46
46
  * nobody to answer for it.
47
47
  */
@@ -52,12 +52,12 @@ export function subagentModelsAreNarrowedV1(turnType: TurnTypeV1): boolean {
52
52
  /**
53
53
  * The catalog one Turn is offered.
54
54
  *
55
- * `assignments` are the Bot's enabled model Assignments, already resolved by
55
+ * `bindings` are the User's enabled model bindings, already resolved by
56
56
  * the Shell; `defaultBinding` is the Bot's own durable binding. A duplicate
57
- * slug is kept once — two Assignments naming one provider model are one choice.
57
+ * slug is kept once — two bindings naming one provider model are one choice.
58
58
  */
59
59
  export function subagentModelCatalogV1(input: {
60
- assignments: readonly TaskModelBindingV1[];
60
+ bindings: readonly TaskModelBindingV1[];
61
61
  defaultBinding?: TaskModelBindingV1;
62
62
  turnType: TurnTypeV1;
63
63
  }): SubagentModelOptionV1[] {
@@ -74,10 +74,10 @@ export function subagentModelCatalogV1(input: {
74
74
  options.push({ slug, binding, isDefault: slug === defaultSlug });
75
75
  };
76
76
  // The default first, so the one slug a narrowed turn renders is always the
77
- // Bot's own binding and never whichever Assignment happens to sort first.
77
+ // Bot's own binding and never whichever binding happens to sort first.
78
78
  if (input.defaultBinding) consider(input.defaultBinding);
79
79
  if (!subagentModelsAreNarrowedV1(input.turnType)) {
80
- for (const assignment of input.assignments) consider(assignment);
80
+ for (const binding of input.bindings) consider(binding);
81
81
  }
82
82
  return subagentModelsAreNarrowedV1(input.turnType)
83
83
  ? options.slice(0, 1)
@@ -106,7 +106,7 @@ export function resolveSubagentModelV1(
106
106
  return {
107
107
  status: "refused",
108
108
  reason:
109
- "this Bot has no enabled model Assignment, so a subagent has no model to run on",
109
+ "this Bot has no enabled model binding, so a subagent has no model to run on",
110
110
  };
111
111
  }
112
112
  return {
@@ -122,7 +122,7 @@ export function resolveSubagentModelV1(
122
122
  reason:
123
123
  offered.length > 0
124
124
  ? `model "${requested}" is not one of this Turn's subagent models (${offered})`
125
- : `model "${requested}" is not available: this Bot has no enabled model Assignment`,
125
+ : `model "${requested}" is not available: this Bot has no enabled model binding`,
126
126
  };
127
127
  }
128
128
  return {
@@ -18,7 +18,6 @@ import {
18
18
  } from "./records.js";
19
19
 
20
20
  const BINDING = {
21
- assignmentId: "asg-1",
22
21
  packageId: "provider-ollama-cloud",
23
22
  capabilityId: "ollama-cloud-models",
24
23
  connectionId: "conn-1",
package/src/records.ts CHANGED
@@ -196,7 +196,6 @@ function subagentFlag(value: unknown, label: string): boolean {
196
196
  * resolves a binding of its own.
197
197
  */
198
198
  export interface TaskModelBindingV1 {
199
- assignmentId: string;
200
199
  packageId: string;
201
200
  capabilityId: string;
202
201
  connectionId: string;
@@ -214,7 +213,6 @@ export function decodeTaskModelBindingV1(
214
213
  subagentExactKeys(
215
214
  candidate,
216
215
  [
217
- "assignmentId",
218
216
  "packageId",
219
217
  "capabilityId",
220
218
  "connectionId",
@@ -225,11 +223,6 @@ export function decodeTaskModelBindingV1(
225
223
  label,
226
224
  );
227
225
  return {
228
- assignmentId: subagentText(
229
- candidate.assignmentId,
230
- 128,
231
- `${label}.assignmentId`,
232
- ),
233
226
  packageId: subagentText(candidate.packageId, 128, `${label}.packageId`),
234
227
  capabilityId: subagentText(
235
228
  candidate.capabilityId,
package/src/store.test.ts CHANGED
@@ -10,7 +10,6 @@ import { TASK_DESKTOP_LEASE_KEY } from "./storage-keys.js";
10
10
 
11
11
  const MODEL = {
12
12
  binding: {
13
- assignmentId: "asg-1",
14
13
  packageId: "provider-ollama-cloud",
15
14
  capabilityId: "ollama-cloud-models",
16
15
  connectionId: "conn-1",