@frockbot/plugin-bot-template 0.3.5 → 0.3.6

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-bot-template",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -24,20 +24,20 @@
24
24
  "typecheck": "vue-tsc --noEmit -p tsconfig.json"
25
25
  },
26
26
  "dependencies": {
27
- "@frockbot/client-core": "0.3.5",
28
- "@frockbot/client-ui": "0.3.5",
29
- "@frockbot/configuration-core": "0.3.5",
30
- "@frockbot/connection-core": "0.3.5",
31
- "@frockbot/kernel-agent-loop": "0.3.5",
32
- "@frockbot/kernel-contracts": "0.3.5",
33
- "@frockbot/plugin-settings": "0.3.5",
34
- "@frockbot/plugin-shell": "0.3.5",
35
- "@frockbot/template-core": "0.3.5",
27
+ "@frockbot/client-core": "0.3.6",
28
+ "@frockbot/client-ui": "0.3.6",
29
+ "@frockbot/configuration-core": "0.3.6",
30
+ "@frockbot/connection-core": "0.3.6",
31
+ "@frockbot/kernel-agent-loop": "0.3.6",
32
+ "@frockbot/kernel-contracts": "0.3.6",
33
+ "@frockbot/plugin-settings": "0.3.6",
34
+ "@frockbot/plugin-shell": "0.3.6",
35
+ "@frockbot/template-core": "0.3.6",
36
36
  "cordis": "4.0.0-rc.8",
37
37
  "vue": "3.5.41"
38
38
  },
39
39
  "devDependencies": {
40
- "@frockbot/plugin-tools": "0.3.5",
40
+ "@frockbot/plugin-tools": "0.3.6",
41
41
  "@types/bun": "1.4.0",
42
42
  "@vitejs/plugin-vue": "6.0.8",
43
43
  "typescript": "5.9.3",
package/src/agent.test.ts CHANGED
@@ -81,10 +81,16 @@ function contextFor(turnType: TurnTypeV1): ToolExecutionContext {
81
81
  };
82
82
  }
83
83
 
84
+ // The tool lives in the `frockbot` namespace, so it is reached the way every
85
+ // namespaced tool is: through the `call_dynamic_tool` envelope (ADR 0023).
84
86
  const call: ToolCall = {
85
87
  id: "call-1",
86
- name: BOT_EXPORT_TEMPLATE_TOOL_V1,
87
- input: {},
88
+ name: "call_dynamic_tool",
89
+ input: {
90
+ namespace: "frockbot",
91
+ toolName: BOT_EXPORT_TEMPLATE_TOOL_V1,
92
+ arguments: {},
93
+ },
88
94
  };
89
95
 
90
96
  async function invoke(
@@ -98,15 +104,39 @@ async function invoke(
98
104
  }
99
105
 
100
106
  describe("bot_export_template", () => {
101
- it("is offered on chat turns only", async () => {
107
+ it("is discoverable on chat turns only", async () => {
108
+ // F36: journey 10 step 1 never called this tool — the Bot invented
109
+ // `package_inspect_self` instead. Registered outside a namespace it
110
+ // appeared in no `<dynamic_tool_catalog>` entry, no
111
+ // `get_dynamic_tools({namespace})` result and no pattern search, so a Bot
112
+ // asked to share itself had nothing to find.
102
113
  const mounted = await mount();
103
114
  try {
104
- const names = (turnType: TurnTypeV1) =>
105
- mounted.root.tools.schemas({ turnType }).map((tool) => tool.name);
106
- expect(names("chat")).toContain(BOT_EXPORT_TEMPLATE_TOOL_V1);
115
+ const discovered = async (turnType: TurnTypeV1) => {
116
+ const context = contextFor(turnType);
117
+ const discovery: ToolCall = {
118
+ id: "call-discover",
119
+ name: "get_dynamic_tools",
120
+ input: { pattern: "template" },
121
+ };
122
+ const preparation = await mounted.root.tools.prepare(
123
+ discovery,
124
+ context,
125
+ );
126
+ if (preparation.kind === "denied") return preparation.result.content;
127
+ return (await mounted.root.tools.executePrepared(preparation, context))
128
+ .content;
129
+ };
130
+ expect(await discovered("chat")).toContain(BOT_EXPORT_TEMPLATE_TOOL_V1);
107
131
  for (const turnType of ["automation", "subagent"] as const) {
108
- expect(names(turnType)).not.toContain(BOT_EXPORT_TEMPLATE_TOOL_V1);
132
+ expect(await discovered(turnType)).not.toContain(
133
+ BOT_EXPORT_TEMPLATE_TOOL_V1,
134
+ );
109
135
  }
136
+ // And it is not offered as a top-level schema, because it is namespaced.
137
+ expect(
138
+ mounted.root.tools.schemas({ turnType: "chat" }).map((t) => t.name),
139
+ ).not.toContain(BOT_EXPORT_TEMPLATE_TOOL_V1);
110
140
  } finally {
111
141
  await mounted.dispose();
112
142
  }
package/src/agent.ts CHANGED
@@ -134,6 +134,13 @@ export function createBotExportTemplateTool(
134
134
  ): ToolDefinition {
135
135
  return {
136
136
  name: BOT_EXPORT_TEMPLATE_TOOL_V1,
137
+ // The `frockbot` namespace, so progressive disclosure (ADR 0023) can find
138
+ // it: it is listed in `<dynamic_tool_catalog>`, returned by
139
+ // `get_dynamic_tools({namespace:"frockbot"})`, and matched by a pattern
140
+ // search for "template" or "export". Registered outside a namespace it was
141
+ // invisible to every one of those, and a Bot asked to share itself
142
+ // invented `package_inspect_self` instead (journey 10 step 1, F36).
143
+ namespace: "frockbot",
137
144
  description: DESCRIPTION,
138
145
  inputSchema: {
139
146
  type: "object",
@@ -69,11 +69,7 @@ async function plan(): Promise<void> {
69
69
  /></span>
70
70
  <span class="import__intro">
71
71
  <strong>Import a Bot template</strong>
72
- <small>
73
- Paste a template link to see exactly what it would create before
74
- anything happens. Importing never brings across Memory, credentials,
75
- or Connections.
76
- </small>
72
+ <small> Paste a template link to see what it would create. </small>
77
73
  </span>
78
74
  </header>
79
75
 
@@ -150,8 +146,8 @@ async function plan(): Promise<void> {
150
146
  <h4>Missing from your catalog</h4>
151
147
  <ul>
152
148
  <li v-for="entry in missing" :key="entry.catalogId">
153
- {{ entry.displayName }} — not in the Catalog generation you are
154
- pinned to, so it will be skipped.
149
+ {{ entry.displayName }} — not available in your catalog, so it will
150
+ be skipped.
155
151
  </li>
156
152
  </ul>
157
153
  </section>
@@ -101,8 +101,8 @@ async function copyLink(share: TemplateShareRecordV1): Promise<void> {
101
101
  <span class="templates__intro">
102
102
  <strong>Share this Bot</strong>
103
103
  <small>
104
- Packs the profile, Bot-authored Skills, Routines, and required
105
- Packages. Memory, credentials, Connections, and Computer files stay
104
+ Packs the profile, Skills, Routines, and the plugins it needs.
105
+ Memory, credentials, connected accounts and computer files stay
106
106
  private.
107
107
  </small>
108
108
  </span>
@@ -125,11 +125,11 @@ async function copyLink(share: TemplateShareRecordV1): Promise<void> {
125
125
  >
126
126
  Packed {{ templates.summary.skills }} Skill(s),
127
127
  {{ templates.summary.routines }} Routine(s),
128
- {{ templates.summary.packages }} Package(s) and
128
+ {{ templates.summary.packages }} plugin(s) and
129
129
  {{ templates.summary.publicServers }} public MCP server(s).
130
130
  <template v-if="templates.summary.needsConnection > 0">
131
- {{ templates.summary.needsConnection }} server(s) are left as a
132
- placeholder the importer fills with their own Connection.
131
+ {{ templates.summary.needsConnection }} server(s) are left for whoever
132
+ imports this to connect themselves.
133
133
  </template>
134
134
  Memory, credentials, and Connections were not included.
135
135
  </p>