@pi-unipi/subagents 0.2.3 → 0.2.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": "@pi-unipi/subagents",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Subagents for UniPi — parallel execution, file locking, workflow integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -60,9 +60,14 @@ describe("Badge generation — tool availability", () => {
60
60
  // ─── Test: Prompt no longer references non-existent tool ───────────
61
61
 
62
62
  describe("Badge generation — prompt fix", () => {
63
- it("prompt asks agent to OUTPUT the title directly (not call a tool)", () => {
63
+ it("prompt includes conversation context inline", () => {
64
64
  const src = readSource("packages/subagents/src/index.ts");
65
65
 
66
+ assert.ok(
67
+ src.includes("Conversation:"),
68
+ "Prompt should include conversation context inline",
69
+ );
70
+
66
71
  assert.ok(
67
72
  src.includes("Reply with ONLY the title"),
68
73
  "Prompt should ask agent to reply with only the title",
@@ -93,6 +98,56 @@ describe("Badge generation — onComplete callback", () => {
93
98
  });
94
99
  });
95
100
 
101
+ // ─── Test: Agent configuration ────────────────────────────────────
102
+
103
+ describe("Badge generation — agent configuration", () => {
104
+ it("badge generation uses 'name-gen' agent type (not 'explore')", () => {
105
+ const src = readSource("packages/subagents/src/index.ts");
106
+
107
+ assert.ok(
108
+ src.includes('manager.spawn(pi, sessionCtx, "name-gen", prompt'),
109
+ "Badge generation should spawn a 'name-gen' agent",
110
+ );
111
+
112
+ assert.ok(
113
+ !src.includes('manager.spawn(pi, sessionCtx, "explore"'),
114
+ "Should NOT use 'explore' — that type can be overridden by user custom agents",
115
+ );
116
+ });
117
+
118
+ it("'name-gen' type is defined in BUILTIN_CONFIGS with empty tools", () => {
119
+ const src = readSource("packages/subagents/src/types.ts");
120
+
121
+ assert.ok(
122
+ src.includes('"name-gen"'),
123
+ "types.ts should define name-gen agent config",
124
+ );
125
+
126
+ assert.ok(
127
+ src.includes('builtinToolNames: []'),
128
+ "name-gen should have empty tool list",
129
+ );
130
+ });
131
+
132
+ it("background agent is isolated (no extensions, no skills, minimal system prompt)", () => {
133
+ const src = readSource("packages/subagents/src/index.ts");
134
+
135
+ assert.ok(
136
+ src.includes("isolated: true"),
137
+ "Should spawn with isolated: true to avoid loading extensions/skills",
138
+ );
139
+ });
140
+
141
+ it("background agent maxTurns is 1 (single response)", () => {
142
+ const src = readSource("packages/subagents/src/index.ts");
143
+
144
+ assert.ok(
145
+ src.includes("maxTurns: 1"),
146
+ "Badge generation agent should have maxTurns: 1",
147
+ );
148
+ });
149
+ });
150
+
96
151
  // ─── Test: Cross-module event bus — the critical fix ───────────────
97
152
 
98
153
  describe("Badge generation — event bus (CRITICAL FIX)", () => {
package/src/index.ts CHANGED
@@ -148,6 +148,19 @@ export default function (pi: ExtensionAPI) {
148
148
  // Build notification details
149
149
  const details = buildNotificationDetails(record, agentActivity.get(record.id));
150
150
 
151
+ // Badge generation: extract name from agent result and set directly.
152
+ // Mark resultConsumed BEFORE the notification check so the main agent
153
+ // never sees this subagent.
154
+ if (record.description === "Generate session name" && record.result && record.status === "completed") {
155
+ const name = record.result.split("\n")[0]?.trim().slice(0, 50) ?? "";
156
+ if (name && !name.startsWith("Error") && !name.includes("error")) {
157
+ try {
158
+ pi.setSessionName(name);
159
+ } catch { /* best effort */ }
160
+ }
161
+ record.resultConsumed = true;
162
+ }
163
+
151
164
  // Send styled notification via message renderer
152
165
  const status = getStatusLabel(record.status, record.error);
153
166
  const durationMs = record.completedAt ? record.completedAt - record.startedAt : 0;
@@ -179,16 +192,6 @@ export default function (pi: ExtensionAPI) {
179
192
  );
180
193
  }
181
194
 
182
- // Badge generation: extract name from agent result and set directly
183
- if (record.description === "Generate session name" && record.result && record.status === "completed") {
184
- const name = record.result.split("\n")[0]?.trim().slice(0, 50) ?? "";
185
- if (name && !name.startsWith("Error") && !name.includes("error")) {
186
- try {
187
- pi.setSessionName(name);
188
- } catch { /* best effort */ }
189
- }
190
- }
191
-
192
195
  pi.events.emit("subagents:completed", {
193
196
  id: record.id,
194
197
  type: record.type,
@@ -354,8 +357,8 @@ export default function (pi: ExtensionAPI) {
354
357
 
355
358
  const summary = event?.conversationSummary ?? "";
356
359
  const prompt = summary
357
- ? `Generate a concise session title (MAX 5 WORDS) for this conversation:\n\n"${summary}"\n\nReply with ONLY the title. No quotes, no explanation, no punctuation.`
358
- : `Generate a concise session title (MAX 5 WORDS) for the current session. Reply with ONLY the title. No quotes, no explanation, no punctuation.`;
360
+ ? `Based on this conversation, generate a concise session title (MAX 5 WORDS). Reply with ONLY the title. No quotes, no explanation, no punctuation.\n\nConversation:\n${summary}`
361
+ : `Generate a concise session title (MAX 5 WORDS) for this session. Reply with ONLY the title. No quotes, no explanation, no punctuation.`;
359
362
 
360
363
  // Try with configured model, fallback to inherit
361
364
  let modelInput: string | undefined = undefined;
@@ -382,11 +385,12 @@ export default function (pi: ExtensionAPI) {
382
385
  // If result is a string (error), resolvedModel stays undefined → inherit parent
383
386
  }
384
387
 
385
- manager.spawn(pi, sessionCtx, "explore", prompt, {
388
+ manager.spawn(pi, sessionCtx, "name-gen", prompt, {
386
389
  description: "Generate session name",
387
390
  model: resolvedModel,
388
391
  isBackground: true,
389
- maxTurns: 3,
392
+ isolated: true,
393
+ maxTurns: 1,
390
394
  });
391
395
  });
392
396
 
package/src/types.ts CHANGED
@@ -44,6 +44,17 @@ export const BUILTIN_CONFIGS: Record<string, AgentConfig> = {
44
44
  promptMode: "append",
45
45
  source: "builtin",
46
46
  },
47
+ "name-gen": {
48
+ name: "name-gen",
49
+ displayName: "Name Generator",
50
+ description: "Minimal agent for generating session names from conversation context.",
51
+ builtinToolNames: [],
52
+ extensions: false,
53
+ skills: false,
54
+ systemPrompt: "You are a session name generator. Generate concise titles from conversation context. Reply with ONLY the title.",
55
+ promptMode: "replace",
56
+ source: "builtin",
57
+ },
47
58
  } as const;
48
59
 
49
60
  /** Memory scope for persistent agent memory. */