@jwilger/pi-development-system 0.89.0 → 0.90.0
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
|
@@ -41,4 +41,4 @@ SOFTWARE.
|
|
|
41
41
|
6. Empty scope (I5 review): `orch/runtime.ts` `availableScopedModels` treats an empty `/scoped-models` as no restriction (pi's meaning) instead of "matches nothing", because every devsys agent declares `models:` and would otherwise be unspawnable by default. Pinned models are also re-applied on resume (`resolveInitialSettings`), since a restored session may hold only inherited history.
|
|
42
42
|
7. Bundled agents outside `src/subagents`: `agents/researcher.md` (devsys `models:` family list) and `agents/reviewer.md` (devsys `models:` list and packet format; description rewritten; upstream `icon` and `modelSuggestions` removed) differ from upstream; `agents/{advisor,implementer,lens-*}.md` are new. The agent file format itself is unchanged.
|
|
43
43
|
8. Thread cap (I7b.1): `orch/manager.ts` `archiveFinished` replaces the hard "Total thread limit reached" check. At `maxThreads` the oldest finished (completed/failed/stopped) thread without a retained descendant is dropped from the registry to make room; the limit is refused only when every kept thread is live, paused or a parent of one. Upstream kept finished threads forever, so long autonomous runs stalled on their own history. A dropped thread cannot be resumed with `agent_steer` (its session file stays on disk).
|
|
44
|
-
9. Registry writes (OOM fix): `index.ts` `persist` signs the registry with `orch/persist-signature.ts` `registrySignature`, which leaves a starting or running thread's status line and partial output out of the change signature. Upstream wrote the whole registry (every thread, about 12 KB each) on every status change; pi never rewrites session entries, so one session grew to 2.3 GB (5,909 snapshots) and pi died loading it. Writes now happen when a thread is added or removed, starts, settles, pauses or is stopped.
|
|
44
|
+
9. Registry writes (OOM fix): `index.ts` `persist` signs the registry with `orch/persist-signature.ts` `registrySignature`, which leaves a starting or running thread's status line and partial output out of the change signature. Upstream wrote the whole registry (every thread, about 12 KB each) on every status change; pi never rewrites session entries, so one session grew to 2.3 GB (5,909 snapshots) and pi died loading it. Writes now happen when a thread is added or removed, starts, settles, pauses or is stopped. A second session still reached 2.0 GB (5,552 snapshots) because a live thread's `sessionLeafId`, `inputTokens`, `outputTokens` and `elapsedMs` change every turn too, so the signature now keeps only a live thread's identity, task and state; `orch/manager.ts` `saved()` omits `sessionLeafId` for a live thread (it would be stale by the time a reload restored it) so a resumed thread opens its session file at the latest leaf.
|
|
@@ -162,7 +162,10 @@ export class ThreadManager {
|
|
|
162
162
|
inputTokens: record.view.inputTokens ?? 0,
|
|
163
163
|
outputTokens: record.view.outputTokens ?? 0,
|
|
164
164
|
};
|
|
165
|
-
|
|
165
|
+
// A live thread is not written per turn (see orch/persist-signature.ts), so its saved
|
|
166
|
+
// leaf would be stale by the time a reload restores it; without one, resuming opens
|
|
167
|
+
// the session file at its latest leaf, which is the right place.
|
|
168
|
+
const sessionLeafId = active(view) ? undefined : this.sessionLeafId(record);
|
|
166
169
|
if (sessionLeafId !== undefined) view.sessionLeafId = sessionLeafId;
|
|
167
170
|
if (active(view)) view.status = view.state === "running" ? "Working" : "Starting";
|
|
168
171
|
return {
|
|
@@ -6,19 +6,31 @@ const LIVE = new Set(["starting", "running"]);
|
|
|
6
6
|
* What decides whether the registry needs writing again.
|
|
7
7
|
*
|
|
8
8
|
* pi appends every `appendEntry` to the session file and never rewrites it, and each
|
|
9
|
-
* registry entry holds every thread (
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* registry entry holds every thread (hundreds of kilobytes once a session has dozens).
|
|
10
|
+
* A running thread changes on every turn: its status line, partial output, session leaf
|
|
11
|
+
* id and token totals. Signing those wrote a snapshot per tool call: one session
|
|
12
|
+
* reached 2.3 GB, a second 2.0 GB after only the status and output were excluded, and
|
|
13
|
+
* pi ran out of memory loading them. None of it is needed to restore a live thread (a
|
|
14
|
+
* reload marks it interrupted and resumes its session file at the latest leaf), so the
|
|
15
|
+
* signature of a live thread is its identity, task and state only. Starting, settling,
|
|
16
|
+
* pausing and adding or removing a thread still write, and a settled thread's leaf,
|
|
17
|
+
* output and totals are signed in full.
|
|
15
18
|
*/
|
|
16
19
|
export function registrySignature(threads: readonly SavedThread[]): string {
|
|
17
20
|
return JSON.stringify(
|
|
18
|
-
threads.map((thread) =>
|
|
19
|
-
LIVE.has(thread.view.state)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
threads.map((thread) => {
|
|
22
|
+
if (!LIVE.has(thread.view.state)) return thread;
|
|
23
|
+
const {
|
|
24
|
+
status,
|
|
25
|
+
output,
|
|
26
|
+
error,
|
|
27
|
+
sessionLeafId,
|
|
28
|
+
inputTokens,
|
|
29
|
+
outputTokens,
|
|
30
|
+
elapsedMs,
|
|
31
|
+
...stable
|
|
32
|
+
} = thread.view;
|
|
33
|
+
return { ...thread, view: stable };
|
|
34
|
+
}),
|
|
23
35
|
);
|
|
24
36
|
}
|