@herbertgao/pi-subagents 0.18.1 → 0.18.2
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/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/agent-manager.ts +5 -4
- package/src/mention-clone.ts +39 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#227](https://github.com/HerbertGao/pi-extensions/pull/227) [`d052f3f`](https://github.com/HerbertGao/pi-extensions/commit/d052f3f3c81e9b6a74d344e9de0f83b8d28341d3) Thanks [@HerbertGao](https://github.com/HerbertGao)! - Retain completed subagent results until they are consumed, including when cleanup runs after ten minutes.
|
|
8
|
+
|
|
9
|
+
Fix a separate Pi 0.87 compatibility issue in mention clones: restore history through SessionManager and provide the live prompt through the before_agent_start hook instead of writing getter-only agent state.
|
|
10
|
+
|
|
3
11
|
## 0.18.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/package.json
CHANGED
package/src/agent-manager.ts
CHANGED
|
@@ -440,8 +440,8 @@ export class AgentManager {
|
|
|
440
440
|
|
|
441
441
|
/**
|
|
442
442
|
* Evicted agents that can still be reached by name, keyed by handle. Outlives
|
|
443
|
-
* the 10-minute record cleanup — that timer
|
|
444
|
-
*
|
|
443
|
+
* the 10-minute record cleanup — that timer bounds memory after results are
|
|
444
|
+
* consumed — and is cleared alongside
|
|
445
445
|
* completed records on session start/switch.
|
|
446
446
|
*/
|
|
447
447
|
private tombstones = new Map<string, AgentTombstone>()
|
|
@@ -483,7 +483,7 @@ export class AgentManager {
|
|
|
483
483
|
this.onCompact = onCompact
|
|
484
484
|
this.onUsage = onUsage
|
|
485
485
|
this.maxConcurrent = maxConcurrent
|
|
486
|
-
// Cleanup completed agents after 10 minutes
|
|
486
|
+
// Cleanup consumed completed agents after 10 minutes
|
|
487
487
|
this.cleanupInterval = setInterval(() => this.cleanup(), 60_000)
|
|
488
488
|
this.cleanupInterval.unref()
|
|
489
489
|
}
|
|
@@ -1640,6 +1640,7 @@ export class AgentManager {
|
|
|
1640
1640
|
for (const [id, record] of this.agents) {
|
|
1641
1641
|
if (record.status === "running" || record.status === "queued") continue
|
|
1642
1642
|
if ((record.completedAt ?? 0) >= cutoff) continue
|
|
1643
|
+
if (!record.resultConsumed) continue
|
|
1643
1644
|
this.removeRecord(id, record)
|
|
1644
1645
|
}
|
|
1645
1646
|
}
|
|
@@ -1648,7 +1649,7 @@ export class AgentManager {
|
|
|
1648
1649
|
* Remove all completed/stopped/errored records immediately.
|
|
1649
1650
|
* Called on session start/switch so tasks from a prior session don't persist.
|
|
1650
1651
|
* Pass skipUnconsumed=true to preserve records the LLM hasn't read yet
|
|
1651
|
-
* (resultConsumed=false)
|
|
1652
|
+
* (resultConsumed=false). The cleanup timer only evicts consumed results.
|
|
1652
1653
|
*/
|
|
1653
1654
|
clearCompleted(skipUnconsumed = false): void {
|
|
1654
1655
|
for (const [id, record] of this.agents) {
|
package/src/mention-clone.ts
CHANGED
|
@@ -64,8 +64,11 @@
|
|
|
64
64
|
import type { Model } from "@earendil-works/pi-ai"
|
|
65
65
|
import {
|
|
66
66
|
buildSessionContext,
|
|
67
|
+
convertToLlm,
|
|
67
68
|
createAgentSession,
|
|
69
|
+
DefaultResourceLoader,
|
|
68
70
|
type ExtensionContext,
|
|
71
|
+
getAgentDir,
|
|
69
72
|
SessionManager,
|
|
70
73
|
type ToolDefinition,
|
|
71
74
|
} from "@earendil-works/pi-coding-agent"
|
|
@@ -163,12 +166,43 @@ export async function runMentionClone(
|
|
|
163
166
|
// `/think` is on anyway. Same shim shape as `modelRuntime` below.
|
|
164
167
|
const thinkingLevel = (ctx as { thinkingLevel?: ThinkingLevel })
|
|
165
168
|
.thinkingLevel
|
|
166
|
-
const
|
|
167
|
-
|
|
169
|
+
const sessionManager = SessionManager.inMemory(ctx.cwd)
|
|
170
|
+
for (const entry of conversation.messages) {
|
|
171
|
+
// The live prompt is copied below. Do not replay the parent's system
|
|
172
|
+
// messages: newer Pi also stores its tool declarations there.
|
|
173
|
+
if ((entry.role as string) === "system") continue
|
|
174
|
+
// Summary messages are projections, not appendable session entries.
|
|
175
|
+
// Preserve exactly the user message Pi would send for each summary.
|
|
176
|
+
if (
|
|
177
|
+
entry.role === "compactionSummary" ||
|
|
178
|
+
entry.role === "branchSummary"
|
|
179
|
+
) {
|
|
180
|
+
for (const message of convertToLlm([entry]))
|
|
181
|
+
sessionManager.appendMessage(message)
|
|
182
|
+
} else {
|
|
183
|
+
sessionManager.appendMessage(entry)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const systemPrompt = ctx.getSystemPrompt?.()
|
|
187
|
+
const created = await runInChildSessionContext(async () => {
|
|
188
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
189
|
+
cwd: ctx.cwd,
|
|
190
|
+
agentDir: getAgentDir(),
|
|
191
|
+
extensionFactories: [
|
|
192
|
+
(pi) => {
|
|
193
|
+
pi.on("before_agent_start", () =>
|
|
194
|
+
systemPrompt ? { systemPrompt } : undefined,
|
|
195
|
+
)
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
})
|
|
199
|
+
await resourceLoader.reload()
|
|
200
|
+
return createAgentSession({
|
|
168
201
|
cwd: ctx.cwd,
|
|
169
202
|
// Nothing about the copy is worth persisting, and an in-memory manager
|
|
170
203
|
// is also what keeps the real session untouched.
|
|
171
|
-
sessionManager
|
|
204
|
+
sessionManager,
|
|
205
|
+
resourceLoader,
|
|
172
206
|
model: ctx.model as Model<never> | undefined,
|
|
173
207
|
...(thinkingLevel && { thinkingLevel }),
|
|
174
208
|
modelRegistry: ctx.modelRegistry,
|
|
@@ -185,21 +219,10 @@ export async function runMentionClone(
|
|
|
185
219
|
// agent-runner's `tools: sessionTools` beside its nested `customTools`.
|
|
186
220
|
tools: [cloneAgentTool.name],
|
|
187
221
|
customTools: [cloneAgentTool],
|
|
188
|
-
} as Parameters<typeof createAgentSession>[0])
|
|
189
|
-
)
|
|
222
|
+
} as Parameters<typeof createAgentSession>[0])
|
|
223
|
+
})
|
|
190
224
|
session = created.session
|
|
191
225
|
|
|
192
|
-
// The clone rebuilds a system prompt from cwd and agentDir, which is close
|
|
193
|
-
// but not the live one — extensions contribute to it per turn. Copy the
|
|
194
|
-
// real thing, so the copy reasons under the instructions the user's model
|
|
195
|
-
// is actually working under.
|
|
196
|
-
const systemPrompt = ctx.getSystemPrompt?.()
|
|
197
|
-
if (systemPrompt) session.agent.state.systemPrompt = systemPrompt
|
|
198
|
-
|
|
199
|
-
// The conversation itself. Pushed rather than assigned so the array the
|
|
200
|
-
// session was built around stays the one it goes on using.
|
|
201
|
-
session.agent.state.messages.push(...conversation.messages)
|
|
202
|
-
|
|
203
226
|
// User text first, reminder after — the order Claude Code's attachment
|
|
204
227
|
// renderer produces, where the reminder trails the message it is about.
|
|
205
228
|
await session.prompt(`${message}\n\n${agentMentionReminder(type)}`)
|