@evandu/super-pi 0.1.60 → 0.1.61

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.
@@ -120,7 +120,6 @@ export type TaskParams = {
120
120
  prompt: string;
121
121
  subagent_type: string;
122
122
  task_id?: string;
123
- background?: boolean;
124
123
  };
125
124
 
126
125
  /** One dispatchable sub-agent, as the server read it from `agents/*.md` at spawn time. */
@@ -154,9 +153,12 @@ export function parseRoster(raw: string | undefined): RosterEntry[] {
154
153
  *
155
154
  * THE CORRECTION. OpenCode's note 1 says a dispatch "runs until it finishes", and this file used to say
156
155
  * the same - while the schema carried a `background` parameter and the code implemented it. So a mode
157
- * that existed was described as though it did not, and the model would never have used it. Note 2 below
158
- * now states that the default is blocking AND that `background` exists, because "delegate several
159
- * independent things at once" is exactly what this roster is shaped for and a model told it cannot.
156
+ * that existed was described as though it did not, and the model would never have used it. The current
157
+ * shape is simpler: there is no blocking mode at all. Every dispatch is asynchronous, every call returns
158
+ * state="running" immediately, and the answer arrives as a follow-up turn. A model that has never been
159
+ * told a dispatch BLOCKS until the child finishes will fire three of them in parallel and find they all
160
+ * read the same pre-delegation state, which is exactly the failure this default avoids. Note 2 below
161
+ * states the always-async contract.
160
162
  *
161
163
  * THE ADDITIONS, notes 7-9, are about COMPOSING dispatches. They were absent because there was
162
164
  * previously nothing on the other end to compose into: the model delegated, read the result, and decided
@@ -178,16 +180,14 @@ When NOT to use this tool:
178
180
 
179
181
  Usage notes:
180
182
  1. Every dispatch starts a SEPARATE agent process that runs until it finishes, so the cost of a delegation is minutes rather than seconds. Delegate work that is genuinely substantial; do not delegate a lookup you could do in one tool call.
181
- 2. Once you have delegated work to a subagent, do not duplicate that work yourself. Continue with non-overlapping tasks, or wait for the result.
182
- 3. When the subagent is done it returns ONE message back to you, wrapped in a <task> element. That result is not visible to the user: if it matters to the user, say so in your own reply.
183
- 4. Each dispatch starts with a FRESH context. Your prompt is all the subagent will know, so it must contain the full task, and it must say exactly what you want back in its final message.
184
- 5. Tell the subagent whether you expect it to WRITE CODE or only to RESEARCH (search, file reads, web fetches), and how to verify its work if it writes. It is not aware of the user's intent.
185
- 6. If a subagent's description says it should be used proactively, use it without being asked.
186
- 7. BY DEFAULT A DISPATCH BLOCKS: the call does not return until that subagent has finished, and its answer comes back to you in this same turn. So you CAN dispatch several in one turn and use each answer before writing the next prompt - which is the normal way to chain specialists.
187
- 8. A LATER DISPATCH MUST CARRY THE EARLIER ONE'S ANSWER IN ITS PROMPT, because the next subagent starts with a fresh context and cannot see what the first one found. The tool does not do this for you. Write the findings you need into the next prompt yourself.
188
- 9. Pass background: true to run this sub-agent ASYNCHRONOUSLY. The dispatch returns immediately with state="running" and the answer arrives as a follow-up turn when the sub-agent finishes. Do NOT use this for a plain shell command - use the run_async tool instead, which is much faster for a one-shot command and does not spin up an entire sub-agent.
189
- 10. To run a SHELL COMMAND in the background (a long build, a test suite, a watcher, anything measured in seconds to minutes), use the run_async tool. Do NOT pass background: true to the task tool for this.
190
- 11. For three or more steps where each depends on the previous one, prefer the workflow tool: it runs the chain server-side and hands each step the previous step's output without you copying it through your context.`;
183
+ 2. The dispatch is ALWAYS ASYNCHRONOUS. The call returns immediately with state="running" and the sub-agent's answer arrives as a follow-up turn when it finishes. You CAN dispatch several in one turn; each returns right away, and the answers stream back as separate follow-up turns in the order the sub-agents settle. Do NOT sleep, poll, or duplicate the dispatch.
184
+ 3. Once you have delegated work to a subagent, do not duplicate that work yourself. Continue with non-overlapping tasks.
185
+ 4. When the subagent is done it returns ONE message back to you, wrapped in a <task> element. That result is not visible to the user: if it matters to the user, say so in your own reply.
186
+ 5. Each dispatch starts with a FRESH context. Your prompt is all the subagent will know, so it must contain the full task, and it must say exactly what you want back in its final message.
187
+ 6. Tell the subagent whether you expect it to WRITE CODE or only to RESEARCH (search, file reads, web fetches), and how to verify its work if it writes. It is not aware of the user's intent.
188
+ 7. If a subagent's description says it should be used proactively, use it without being asked.
189
+ 8. To CHAIN sub-agents, write the first dispatch's expected answer INTO the second dispatch's prompt, because the next sub-agent starts with a fresh context and cannot see what the first one found. The tool does not do this for you. For three or more chained steps, prefer the workflow tool: it runs the chain server-side and hands each step the previous step's output without you copying it through your context.
190
+ 9. To run a SHELL COMMAND in the background (a long build, a test suite, a watcher, anything measured in seconds to minutes), use the run_async tool. This tool is for delegating to a specialist sub-agent, not for plain commands.`;
191
191
 
192
192
  /**
193
193
  * The roster block, OpenCode's `describeTask()` reduced to its two jobs: the ids that are legal, and
@@ -345,7 +345,10 @@ export async function executeTask(
345
345
  prompt: params.prompt,
346
346
  description: params.description,
347
347
  depth: config.depth,
348
- background: false,
348
+ // ALWAYS ASYNCHRONOUS. The model never blocks on a sub-agent - a sub-agent takes minutes, and a
349
+ // dispatch that blocks would freeze the primary turn for the whole of that. The result arrives
350
+ // as a follow-up turn when the sub-agent finishes; the call returns state="running" immediately.
351
+ background: true,
349
352
  // Always sent, even when undefined, so a body that omits the field is unambiguously a caller that
350
353
  // did not have one - which the server treats as a refusal, not as a legacy request to let through.
351
354
  capability: config.capability,
@@ -366,22 +369,24 @@ export async function executeTask(
366
369
 
367
370
  // No run id means nothing ran: either the server refused before spawning, or the body was unreadable.
368
371
  // "refused" says so, where "unknown" would imply a run exists somewhere whose output is merely absent.
372
+ // The dispatch is ALWAYS async, so the only shape a successful response has here is state="running".
373
+ // A finished run that came back synchronously would mean the server ignored background:true, which is
374
+ // the refusal below, not a happy path.
369
375
  const id = payload.run?.id ?? "refused";
370
- if (params.background === true && payload.run?.status === "running") {
376
+ if (payload.run?.status === "running") {
371
377
  return text(`<task id="${id}" state="running">\n<summary>${params.description.trim() || params.subagent_type}</summary>\n<task_result>The task is working in the background. You will be notified automatically when it finishes. Do not sleep, poll for progress, ask the task for status, or duplicate this task's work. Continue with non-overlapping work.</task_result>\n</task>`);
372
378
  }
373
- const completed = payload.run?.status === "completed";
374
- const body = completed
375
- ? payload.output ?? ""
376
- : payload.error ?? `The sub-agent run finished as ${JSON.stringify(payload.run?.status ?? "unknown")} without saying why.`;
379
+ // The server should never answer a background dispatch with a finished run, because background:true
380
+ // returns 202 immediately. If it does, surface the reason rather than pretending the answer is in hand.
381
+ const body = payload.error ?? `The sub-agent run finished as ${JSON.stringify(payload.run?.status ?? "unknown")} without saying why.`;
377
382
  return text(
378
383
  renderTaskResult({
379
384
  id,
380
- state: completed ? "completed" : "error",
385
+ state: "error",
381
386
  summary: params.description.trim() ? `${params.description.trim()} (${params.subagent_type})` : `${params.subagent_type}`,
382
- text: payload.outputTruncated && completed ? `${body}\n\n[This answer was truncated at 50 KB by the server; the full run is recorded in Super Pi.]` : body,
387
+ text: body,
383
388
  }),
384
- !completed,
389
+ true,
385
390
  );
386
391
  }
387
392
 
@@ -50,7 +50,6 @@ const Parameters = Type.Object({
50
50
  prompt: Type.String({ description: "The task for the agent to perform" }),
51
51
  subagent_type: Type.String({ description: "The type of specialized agent to use for this task" }),
52
52
  task_id: Type.Optional(Type.String({ description: "Resume a previous task when supported" })),
53
- background: Type.Optional(Type.Boolean({ description: "Run asynchronously and deliver the result as a follow-up message" })),
54
53
  });
55
54
  const QuestionParameters = Type.Object({ question: Type.String(), options: Type.Array(Type.String(), { minItems: 1 }), multiple: Type.Optional(Type.Boolean()), extraNote: Type.Optional(Type.Boolean()) });
56
55
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evandu/super-pi",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "description": "Web control plane and companion for Pi",
5
5
  "license": "MIT",
6
6
  "type": "module",