@llblab/pi-kit 0.18.0 → 0.18.1
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 +6 -0
- package/README.md +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-state-flow/README.md +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +3 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/package.json +5 -5
- package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +27 -82
- package/node_modules/@llblab/pi-state-flow/docs/performance.md +2 -2
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +1 -1
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +3 -3
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/package.json +5 -5
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@llblab/pi-kit` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.18.1 - 2026-09-20
|
|
6
|
+
|
|
7
|
+
- `Passive State Flow Guidance`: Advances the exact State Flow pin to `0.16.3`, requiring finalization barriers only in active episodes while preventing gratuitous final-only patches during passive memory use.
|
|
8
|
+
- `Compatibility Contract`: Carries the minimum Pi SDK version `0.84.4` without an artificial upper peer-dependency bound and removes stale compatibility evidence without dropping supported storage migrations or current safety checks.
|
|
9
|
+
- `Package Cohort`: Keeps every other bundled package at its current exact version; the package set, resource inventory, and explicit load order remain unchanged.
|
|
10
|
+
|
|
5
11
|
## 0.18.0 - 2026-09-18
|
|
6
12
|
|
|
7
13
|
- `Telegram Lifecycle Gateway`: Advances the exact Telegram pin to `0.50.0`, replacing the session-specific technical command with one guarded internal gateway for runtime-armed lifecycle actions while preserving `/new` settlement, continuity, and terminal-result guarantees.
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Package links lead to the owning repositories for usage, documentation, issues,
|
|
|
14
14
|
| [`@llblab/pi-clean-room`](https://github.com/llblab/pi-clean-room) | `0.1.1` | Isolated nested Pi TUI with explicitly selected extensions |
|
|
15
15
|
| [`@llblab/pi-codex-usage`](https://github.com/llblab/pi-codex-usage) | `0.10.0` | Compact Codex/Spark subscription-limit and Business credit-usage status |
|
|
16
16
|
| [`@llblab/pi-grow-loop`](https://github.com/llblab/pi-grow-loop) | `0.8.1` | Visible continuation scheduling and bounded worker Skills |
|
|
17
|
-
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.16.
|
|
17
|
+
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.16.3` | Incremental scoped state/context/memory compiler with mode-aware passive guidance, proportional operational guidance, intentional agency, reactive dangling-reference diagnostics, safe compaction, and exact publication |
|
|
18
18
|
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.50.0` | Telegram companion with native fresh-session replacement, a guarded internal lifecycle gateway, buffered thinking cadence, adaptive Thread continuity, exact queues, files, voice, controls, and Generative Apps guidance |
|
|
19
19
|
| [`@llblab/skills`](https://github.com/llblab/skills) | `1.15.0` | Portable workflows for engineering, review, design, context maintenance, and other focused tasks |
|
|
20
20
|
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
- Explicit `/state-flow-start` creates the State Flow directory when missing and returns after locally usable runtime acceptance for normal `turn-end`/`off` policy. If Git is installed, initialize an exact-root Git repository when needed, including a populated file-only store, preserving all existing bytes and unrelated files; an ancestor repository is not a valid substitute. Skip full predecessor-format migration planning only when all exact legacy snapshot names are absent, and defer Markdown freshness discovery until before the next enabled inference. If Git is absent, use file persistence. Manual-mode startup/status/restore do not initialize Git; configured automatic start of a genuinely new session uses the same initialization as explicit start. Never create external accounts, remote repositories, credentials, or remote configuration; those remain operator-owned. Never auto-import, delete, or reset files/history in a previous Knowledge-backed store; old branch revisions require their original Git history to remain available in the selected store. `/state-flow-start` must initialize missing global, CWD, and current-session checkpoint/tail pairs plus session config/meta through compare-and-swap publication when required, enable only the current session branch, and bootstrap prior conversation when needed. Explicit start on a proven pre-runtime branch (no checkpoint or an ordinary-disabled marker) establishes an empty session origin rather than importing a later same-session layer; validate existing runtime identity, retain shared streams unchanged, and preserve later branch data in cold Git history. Ordinary new sessions remain manual unless agent-level `autoStart` is true; CWD materialization alone grants no automatic activation. Configured new sessions may initialize missing CWD state and receive distinct empty session layers while inheriting global/CWD values. Resumed and tree-selected branches restore their own config and temporal lineage, regardless of the global flag.
|
|
45
45
|
- `/state-flow-stop` returns to the configured passive bootstrap/tool combination and must persist only the current session/branch's `config.enabled = false` and necessary runtime provenance, preserving all semantic checkpoints/tails and creating no semantic transition. Retain a frozen handoff plus the active user-run trajectory (including later tool results), post-stop conversation, and foreign context-bearing custom messages across same-physical-session reload/resume/tree. Exclude completed pre-run conversation and private State Flow validation feedback; idle Stop does not retain the completed run. Active restart replaces passive mode but uses that bounded boundary for its one migration run; new and forked physical sessions inherit neither projection. It does not rewrite agent-level `autoStart` or change its policy for future new sessions.
|
|
46
46
|
- After an accepted non-bootstrap run settles with no pending input, State Flow may request native manual compaction under a generation-private marker only when public `getContextUsage()` reports at least 24,000 tokens. Keep the complete latest accepted user iteration, store only revision/step identity in details, and never duplicate state in the summary. Unknown or smaller usage skips compaction; a benign native refusal releases the attempt for later work. Skip prefixes containing foreign custom context. Never customize user manual or native threshold/overflow compaction, discard unfinished pre-patch work, create a State Flow origin, or rewrite Pi's append-only JSONL/tree.
|
|
47
|
-
- Keep the injected runtime protocol compact and normative; put rationale and extended explanation in README rather than the model prompt.
|
|
47
|
+
- Keep the injected runtime protocol compact and normative; put rationale and extended explanation in README rather than the model prompt. Foreign comment handling remains owned by other extensions.
|
|
48
48
|
- Do not claim strict boundedness for state, the current run trajectory, the turn specification, or the external full trace.
|
|
49
49
|
- Remain extension-agnostic in core semantics, storage, and inference: core modules never import, name, special-case, or encode policy for another extension or transport. One optional leaf presentation adapter (`lib/telegram.ts`) may import public `pi-telegram` membranes to mirror the live status on exactly one main-menu section button and expose the same start/stop affordances already owned by `state-flow-start` and `state-flow-stop`; it must fail open when the transport is absent or its registry is unready and must never alter core behavior.
|
|
50
50
|
- Activate State Flow model tools while an episode is enabled or passive tools are configured; preserve every unrelated active tool when toggling them. Passive reads never initialize storage, while an explicit passive patch may initialize or migrate storage without enabling episode barriers, continuation, or compaction. Keep mutation confined to `patch_state` and historical observation read-only.
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.16.3: Passive guidance and compatibility cleanup
|
|
8
|
+
|
|
9
|
+
- `Passive finalization guidance`: Makes the always-available `patch_state` tool contract mode-aware, requiring `final:true` only for active episodes and explicitly forbidding final-only calls in passive turns so tool-level guidance no longer contradicts passive runtime context.
|
|
10
|
+
- `Pi compatibility range`: Declares `0.84.4` as the minimum Pi SDK version without an upper peer-dependency bound, replaces stale candidate reports and historical run internals with a concise tested-stack contract, and removes dead legacy test scaffolding plus retired HTML-envelope fixtures without dropping supported storage migrations or current negative-boundary coverage.
|
|
11
|
+
|
|
7
12
|
## 0.16.2: Passive first-CWD memory hotfix
|
|
8
13
|
|
|
9
14
|
- `Passive first-CWD memory`: Treats global-only storage as a valid passive-memory state before the current CWD has ever materialized, projecting an empty CWD overlay instead of warning that shared storage is incomplete; CWD-without-global storage still fails closed.
|
|
@@ -26,7 +26,7 @@ The agent curates what matters; the extension validates, persists, and projects
|
|
|
26
26
|
|
|
27
27
|
## Quick start
|
|
28
28
|
|
|
29
|
-
Requires Pi `0.84.4
|
|
29
|
+
Requires Pi `0.84.4` or newer and Node.js `22.19.0` or newer. There is no declared upper Pi version bound; see the [SDK compatibility matrix](docs/compatibility.md) for exact tested stacks. Git is optional; using it requires a configured commit identity.
|
|
30
30
|
|
|
31
31
|
From npm:
|
|
32
32
|
|
|
@@ -619,10 +619,10 @@ export default function stateFlowExtension(pi, options = {}) {
|
|
|
619
619
|
pi.registerTool({
|
|
620
620
|
name: PATCH_STATE_TOOL_NAME,
|
|
621
621
|
label: "Patch State",
|
|
622
|
-
description: "The sole State Flow semantic mutation protocol. Supply any combination of global, cwd, and session patches; all supplied scopes commit atomically.
|
|
623
|
-
promptSnippet: "Atomically patch global/cwd/session; final:true
|
|
622
|
+
description: "The sole State Flow semantic mutation protocol. Supply any combination of global, cwd, and session patches; all supplied scopes commit atomically. In an active State Flow episode, set final:true when the current iteration may finish at a later turn_end; use {final:true} when no semantic update is needed. Passive turns have no terminal barrier: never call patch_state only to set final:true. This call must be the only State Flow barrier in its assistant response.",
|
|
623
|
+
promptSnippet: "Atomically patch global/cwd/session; active episodes use final:true before turn_end",
|
|
624
624
|
promptGuidelines: [
|
|
625
|
-
"Use patch_state for durable semantic changes.
|
|
625
|
+
"Use patch_state for durable semantic changes. Only in an active State Flow episode, make the iteration terminal-eligible before a final answer with final:true, optionally alongside atomic global/cwd/session patches. In passive mode, never call patch_state only to set final:true.",
|
|
626
626
|
"Use patch_state as reconciliation, not append-only notes: place new knowledge at the narrowest valid scope and remove superseded or completed state from touched branches.",
|
|
627
627
|
"Call patch_state alone in an assistant response; after its acknowledgement, further reasoning, tools, and later patch_state calls remain allowed.",
|
|
628
628
|
],
|
|
@@ -10,5 +10,5 @@ export declare function separatedFailure(error: unknown): Error;
|
|
|
10
10
|
/** The compact model-facing contract. Semantic writes never travel through terminal prose. */
|
|
11
11
|
export declare function stateFlowProtocol(bootstrap: boolean): string;
|
|
12
12
|
export declare function assistantToolCallCount(content: unknown): number;
|
|
13
|
-
/** The post-handler assistant
|
|
13
|
+
/** The accepted post-handler assistant text is authoritative. */
|
|
14
14
|
export declare function finalizedAssistantResponse(message: AgentMessage): string;
|
|
@@ -89,7 +89,7 @@ export function assistantToolCallCount(content) {
|
|
|
89
89
|
return 0;
|
|
90
90
|
return content.filter((block) => typeof block === "object" && block !== null && block.type === "toolCall").length;
|
|
91
91
|
}
|
|
92
|
-
/** The post-handler assistant
|
|
92
|
+
/** The accepted post-handler assistant text is authoritative. */
|
|
93
93
|
export function finalizedAssistantResponse(message) {
|
|
94
94
|
if (message.role !== "assistant" || !Array.isArray(message.content)) {
|
|
95
95
|
throw new Error("Finalized State Flow turn does not contain an assistant response");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-state-flow",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Incremental scoped state/context/memory compiler for Pi, inspired by SKILL.state",
|
|
6
6
|
"keywords": [
|
|
@@ -66,10 +66,10 @@
|
|
|
66
66
|
"node": ">=22.19.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@earendil-works/pi-agent-core": "
|
|
70
|
-
"@earendil-works/pi-ai": "
|
|
71
|
-
"@earendil-works/pi-coding-agent": "
|
|
72
|
-
"@earendil-works/pi-tui": "
|
|
69
|
+
"@earendil-works/pi-agent-core": ">=0.84.4",
|
|
70
|
+
"@earendil-works/pi-ai": ">=0.84.4",
|
|
71
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4",
|
|
72
|
+
"@earendil-works/pi-tui": ">=0.84.4"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@earendil-works/pi-tui": "0.84.4",
|
|
@@ -1,101 +1,46 @@
|
|
|
1
1
|
# Pi SDK compatibility
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
State Flow requires matching Pi SDK packages at `>=0.84.4` without an upper peer-dependency bound. Keep `pi-coding-agent`, `pi-agent-core`, `pi-ai`, and `pi-tui` on the same release line.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The peer range permits newer releases so npm does not impose an artificial ceiling. It does not claim that every future SDK release has been tested. Revalidate the public host seams below when adopting a new Pi release line.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Tested stacks
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The current repository-local stack uses Linux/x64, Node 26.8.1, Git 2.55.0, and Pi SDK 0.84.4.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
| Pi SDK stack | Validation | Evidence status |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| 0.84.4 | Build, typecheck, import, package dry-run, 445/445 tests | Current full-suite baseline |
|
|
14
|
+
| 0.85.1 | Build, typecheck, import, full suite | Earlier compatibility baseline; not rerun for every later State Flow change |
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
| --- | --- | --- | --- |
|
|
15
|
-
| 0.84.4 / 0.84.4 / 0.84.4 | 0.84.4 / 1.3.7 | Pass / pass | 417/417 |
|
|
16
|
-
| 0.85.1 / 0.85.1 / 0.85.1 | 0.85.1 / 1.3.7 | Pass / pass | 417/417 |
|
|
17
|
-
|
|
18
|
-
The first row is the repository-local stack. The second used a disposable copy of the same working source, with read-only dependency links to the already installed 0.85.1 SDK and its actual AI/agent-core/pi-tui graph. All commands exited zero for the accepted results. The repository lockfile still resolves 0.84.4; broadening its root peer metadata did not install or upgrade dependencies. No live Pi process, installation, production session or state store was modified.
|
|
19
|
-
|
|
20
|
-
Both stacks passed `npm run validate` after adding the four [fatal-writer interruption witnesses](temporal-acceptance.md#fatal-writer-interruption). No runtime correction was needed: runtime SHA-256 remains `ce820cd33c34c4c882c11fc55e93f3914cfc8dffae57683e32cdcaa70f225cd2` from the [context-copy correction](performance.md#context-projection-and-trajectory-selection). Sorted `index.ts`, `lib/*.ts` and `tests/*.ts`, framed as path + NUL + bytes + NUL, now yield `1c5fafc1433631fed33177381e925eeeca52827932ba327690f615d2a4db81ba`. Copied/original source, runtime, test and package bytes were checked unchanged through validation, along with both selected dependency-resolution graphs and their manifests. These hashes do not cover every installed binary or environmental influence. The [benchmark workload fingerprint](performance.md) remains `b861fae36798bf76f56f411cc654c70fc948597bb84cc7a422c83f69ba1ca3e9`. Subsequent [matched runtime-performance controls](performance.md#matched-final-candidate-controls) use the 0.84.4 graph only, not a two-SDK timing comparison. The earlier fork/context witnesses remain included; these results do not replace separate integrated-candidate acceptance.
|
|
21
|
-
|
|
22
|
-
### Post-measurement integrated acceptance
|
|
23
|
-
|
|
24
|
-
After the nine-invocation performance series, inline review traced accumulated Git/CAS, provenance, worker ownership, fork/recovery, Stop/context and discovery changes against their callers and negative/native witnesses, without a confirmed blocker in that inspected closure. Separate `state-flow-integrated-0844` and `state-flow-integrated-0851` Runs repeated `npm run validate`: each passed 417/417 with no failed, cancelled, skipped or todo tests, plus typecheck and import-check, and actual command exit zero. Full captures are 47,957 and 47,950 bytes. All 78 selected runtime/test/package files and both actual dependency graphs remained unchanged; documentation is separately reviewed rather than represented by that source hash.
|
|
25
|
-
|
|
26
|
-
The twenty-property map resolves its quoted witnesses; that structural check is not exhaustive semantic proof. Domain validation reports 31 source files/133 acyclic local edges and no reverse entrypoint imports, with 25 existing header warnings. Context validation reports zero errors/five warnings. The package dry run includes 44 files and no tests. This accepts the local candidate within the documented synthetic/Linux/SDK boundaries, not arbitrary-host compatibility, production-incident attribution, publication permission or remote release-CI success. That checkpoint preceded the final compaction/status slice and its intentional 0.10.0 version alignment.
|
|
27
|
-
|
|
28
|
-
The final slice adds seven compaction policy/race tests and two native lifecycle witnesses, bringing the complete repository-local 0.84.4 suite to 426/426 with typecheck/import-check. On 0.85.1, all affected policy/status and native compaction/tree tests plus typecheck pass; the operator declined a redundant second full-suite repetition after this focused equivalence evidence. Native completed-history compaction preserves full JSONL/tree/state/UUID while shortening active/resumed entries without another model summary; threshold compaction before the first patch remains Pi-owned. Package version is 0.10.0. Remote release CI remains authoritative for the tagged tree.
|
|
29
|
-
|
|
30
|
-
Matching versions do not imply one physical dependency instance. Before/after resolution walks retain separate root and SDK-local 0.84.4 AI/agent-core copies and three TypeBox 1.3.7 locations in the repository installation. The first row describes that actual graph, not a deduplicated installation. The disposable 0.85.1 copy explicitly shares the SDK's AI/agent-core/pi-tui instances. Record canonical resolution edges as well as versions for comparisons; no dependency installation was changed to force a verifier assumption.
|
|
31
|
-
|
|
32
|
-
The focused parent-traversal and barrier cohort passed 3/3 on each stack. The earlier 0.85.1 native cohort passed 10/10: large state/answers, selected-tree restoration, quit/reload push ownership, ordinary/bootstrap mid-tool Stop, compaction/tree/restart, scoped barriers, historical reads, and sibling-tool rejection. The full suite includes those witnesses plus benchmark, persistence, provenance, migration and concurrency contracts; tests are available in a source checkout, not the published runtime package.
|
|
16
|
+
Only exact matching stacks that were actually exercised are test evidence. Mixed SDK versions and untested newer releases are permitted by package metadata but remain unverified.
|
|
33
17
|
|
|
34
18
|
## Public host seams
|
|
35
19
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- `session-manager.js` / `session-manager.d.ts`: Read-only extension context exposes `getLeafEntry()`, `getEntry(id)` and each entry's `parentId`. Both lookups use the native ID map; `getBranch()` instead walks to the root and reverses a newly allocated path. State Flow now uses that public parent traversal for preflight without deleting or replacing native history.
|
|
39
|
-
- `agent-session.js`, `_handleAgentEvent()` / `_installAgentToolHooks()`, and agent-core's `agent-loop.js`: `message_end` extension handlers run before session persistence; the awaited event then appends the accepted assistant message before tool preflight. Inspect that synchronized current assistant, not a presumed last persisted assistant inside `message_end`. The native sibling-tool regression is the executable barrier witness.
|
|
40
|
-
- `sdk.js` and `extensions/runner.js`, `emitContext()`: Pi connects context transformation to the extension runner, which first `structuredClone`s native messages. State Flow projection runs after that host copy. Reducing extension traversal cannot make total inference work independent of history size.
|
|
41
|
-
- `agent-session.js`, `prompt()` / `reload()` / `dispose()`: The system prompt is composed at `before_agent_start`; Stop can change tools/projection but not that already composed prompt for the current run. Reload awaits `session_shutdown` before replacement. Bare disposal invalidates/disconnects without emitting shutdown; use the [embedding contract](architecture.md#embedding).
|
|
42
|
-
- `agent-session-runtime.js`, `teardownCurrent()`: Owner-driven new/resume/fork aborts the outgoing session, awaits shutdown, then disposes and creates the replacement. Active-push witnesses now cover new, same-file resume and fork teardown before invalidation, alongside quit and actual reload. Correct teardown does not imply successful fork restoration.
|
|
43
|
-
- `sdk.js`, `createAgentSession()`: Session selection precedes default resource/extension loading. No extension-only pre-session resolver seam was established; native default continuation remains an [external integration boundary](architecture.md#session-continuation).
|
|
44
|
-
|
|
45
|
-
These observations establish the specific seams used here, not compatibility with every Pi UI mode, extension combination, provider or operating system. Native tests use deterministic faux inference, temporary sessions/stores and local remotes. An installed SDK version does not fingerprint a still-running host. Actual-process incident attribution remains unproven; final comparable measurements and integrated acceptance remain in [BACKLOG.md](../BACKLOG.md).
|
|
46
|
-
|
|
47
|
-
## Native replacement witnesses
|
|
20
|
+
State Flow depends on these public Pi SDK behaviors:
|
|
48
21
|
|
|
49
|
-
|
|
22
|
+
- Extension lifecycle events and branch metadata for start, stop, reload, resume, fork, and tree navigation.
|
|
23
|
+
- Read-only session parent traversal through `getLeafEntry()` and `getEntry(id)`.
|
|
24
|
+
- `message_end` and `turn_end` ordering before accepted assistant messages are reconciled.
|
|
25
|
+
- Context transformation through the extension runner.
|
|
26
|
+
- `getContextUsage()` and native compaction hooks.
|
|
27
|
+
- Sequential tool execution and tool-call preflight.
|
|
28
|
+
- Session replacement awaiting outgoing shutdown before invalidation.
|
|
50
29
|
|
|
51
|
-
|
|
52
|
-
- The exact shutdown reason/target, child exit and a claimable lease at `setBeforeSessionInvalidate()`, before a successor can start.
|
|
53
|
-
- Byte-identical outgoing JSONL and session checkpoint/tail/config/meta, the same selected leaf, and exact cold state at the accepted revision.
|
|
54
|
-
- An empty private layer plus inherited shared state for configured new sessions, and exact selected state/identity for same-file resume.
|
|
55
|
-
- No old-generation relaunch or queue writes after replacement; only a valid successor attempts the exact pending target and acknowledges its controlled child result.
|
|
30
|
+
Compatibility with those seams does not prove every UI mode, provider, operating system, extension combination, or future SDK release.
|
|
56
31
|
|
|
57
|
-
|
|
32
|
+
## Validation procedure
|
|
58
33
|
|
|
59
|
-
|
|
34
|
+
Validate another Pi SDK line in an isolated copy so the live extension, sessions, and runtime store remain unchanged:
|
|
60
35
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
1. Copy the intended current source, including retained uncommitted files and tests, to a fresh temporary directory. Do not substitute baseline `HEAD` for a dirty candidate. Give the copy its own synthetic Git `HEAD` for benchmark source-identity checks; never copy production session/store data.
|
|
68
|
-
2. Create a real `node_modules` directory in the copy. Link the existing development dependencies, then link `@earendil-works/pi-coding-agent` to the selected installed SDK and AI/agent-core/pi-tui to the dependencies actually resolved by that SDK. Do not use `--preserve-symlinks` or install into the live package. Verify the SDK and extension resolve the same selected dependency instances.
|
|
69
|
-
3. Resolve import-only package manifests with `findPackageJSON(name, pathToFileURL(ownerManifest))`, not `require.resolve(name)`. Record canonical manifest paths, package names/versions and hashes before and after testing. For example, run the following inside the copy:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
node --input-type=module <<'JS'
|
|
73
|
-
import { findPackageJSON } from 'node:module';
|
|
74
|
-
import { readFileSync, realpathSync } from 'node:fs';
|
|
75
|
-
import { pathToFileURL } from 'node:url';
|
|
76
|
-
const owner = pathToFileURL(`${process.cwd()}/package.json`);
|
|
77
|
-
for (const name of ['pi-coding-agent', 'pi-ai', 'pi-agent-core', 'pi-tui']) {
|
|
78
|
-
const path = realpathSync(findPackageJSON(`@earendil-works/${name}`, owner));
|
|
79
|
-
console.log(path, JSON.parse(readFileSync(path, 'utf8')).version);
|
|
80
|
-
}
|
|
81
|
-
JS
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Use a fresh `PI_CODING_AGENT_DIR`, `PI_OFFLINE=1`, `GIT_CONFIG_NOSYSTEM=1` and a temporary `GIT_CONFIG_GLOBAL` containing only a synthetic commit identity and disabled commit signing. Fixtures already supply in-memory credentials, no model-catalog refresh and explicit resource/session roots. Leave fixture-local Git hooks enabled: tests intentionally use temporary `pre-receive`/`post-receive` hooks.
|
|
85
|
-
|
|
86
|
-
Inside that prepared copy, the compatibility checks are ordinary project commands:
|
|
36
|
+
1. Copy the complete candidate source, including retained uncommitted changes, into a temporary directory.
|
|
37
|
+
2. Install or link one matching version of `pi-coding-agent`, `pi-agent-core`, `pi-ai`, and `pi-tui`.
|
|
38
|
+
3. Confirm all four packages resolve to the intended release line.
|
|
39
|
+
4. Use isolated Pi agent/session directories and synthetic Git identity; do not copy production session or State Flow data.
|
|
40
|
+
5. Run:
|
|
87
41
|
|
|
88
42
|
```bash
|
|
89
|
-
npm run
|
|
90
|
-
npm run check
|
|
91
|
-
node --experimental-strip-types --test \
|
|
92
|
-
--test-name-pattern='tool preflight walks only|patch_state is the only tool|real Pi executes only patch_state|replacement closes its outgoing publisher' \
|
|
93
|
-
tests/extension.test.ts tests/integration.test.ts
|
|
94
|
-
npm test
|
|
43
|
+
npm run validate
|
|
95
44
|
```
|
|
96
45
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
### Rejected setup and correction
|
|
100
|
-
|
|
101
|
-
The first 0.85.1 full run passed 395/397 because the temporary global Git config incorrectly set `core.hooksPath` to an empty directory. This disabled two fixtures' hooks: prepared receipts no longer observed the synthetic post-push write, and file-to-Git adoption no longer observed the intentionally pending push. The same two failures reproduced on 0.84.4 with that config. Removing only the temporary override made both witnesses pass on both SDKs, followed by 397/397 on 0.85.1. No runtime or test correction was needed; the failed run is not an SDK incompatibility or a successful full-suite result.
|
|
46
|
+
A successful focused test does not replace the full suite. Record the exact dependency graph and command exit for any compatibility claim.
|
|
@@ -131,7 +131,7 @@ Native controls have two rather than three inferences per request and no State F
|
|
|
131
131
|
- **Short runs are not uniformly faster:** At twenty 8 KiB requests, B2's 1132.5ms p50 exceeds A1's 1115.7ms despite fewer calls. Both B short-case p95 values exceed A1's 1140.8ms. A1/A2 also change materially without code changes: long 8 KiB run p50 is 1373.7 → 1165.1ms, while short 128 KiB is 1602.8 → 1234.7ms. Keep these observations rather than collapsing the controls into one average.
|
|
132
132
|
- **No history-independent latency claim:** B1's first-context medians rise 316.6 → 387.4ms and 297.6 → 347.5ms with unchanged 31 calls; B2's 128 KiB case rises 311.9 → 388.2ms. Identical counts do not bound internal Git work, host cloning, allocation or scheduling. These samples do not isolate the cause.
|
|
133
133
|
- **Projection and native trace remain distinct:** First resumed enabled contexts are exactly 9694 / 9712 bytes at 8 KiB and 132574 / 132592 at 128 KiB across all four invocations. Native first-context medians grow from about 105 KB to 1.054 MB. Preserving a compact delivered context does not bound semantic state, the full native trace or Pi's pre-projection history clone.
|
|
134
|
-
- **Remaining evidence is separate:** This block covers the 4 KiB-read lifecycle comparison only. The larger-read pair and current large-state boundary follow below; the publisher pair also follows.
|
|
134
|
+
- **Remaining evidence is separate:** This block covers the 4 KiB-read lifecycle comparison only. The larger-read pair and current large-state boundary follow below; the publisher pair also follows. Repository validation is recorded independently from these measurements. It establishes neither the production incident's cause nor real-provider latency or universal responsiveness.
|
|
135
135
|
|
|
136
136
|
### Larger delivered history: matched A/B pair
|
|
137
137
|
|
|
@@ -191,7 +191,7 @@ Reported mixed-attempt p50/p95 milliseconds are A/B: same-session 3.1/465.9 vers
|
|
|
191
191
|
|
|
192
192
|
All nine planned invocations are accepted, sequential and source-bound; the seven lifecycle invocations contain 108 preserved copied probes, excluding six setup probes. Complete captures, actual exits and guards are retained with `/tmp/state-flow-final-controls-CzaHqM/final-series-receipts.json`. Lifecycle distributions were independently recomputed from retained samples; publisher aggregates have the narrower evidence boundary above.
|
|
193
193
|
|
|
194
|
-
The candidate reduces proven Git/allocation work and shows lower enabled long-case medians in these controls while preserving selected state and accepted continuation. It does not eliminate native history handling, payload cost, timing variability or safe contention refusal. Adverse short-case/tail observations remain. No further runtime correction is justified by these measurements alone; original production slowdown attribution remains unproven. Separate
|
|
194
|
+
The candidate reduces proven Git/allocation work and shows lower enabled long-case medians in these controls while preserving selected state and accepted continuation. It does not eliminate native history handling, payload cost, timing variability or safe contention refusal. Adverse short-case/tail observations remain. No further runtime correction is justified by these measurements alone; original production slowdown attribution remains unproven. Separate repository validation, not this measurement closure, governs local candidate readiness; release authorization and remote CI remain separate gates.
|
|
195
195
|
|
|
196
196
|
The following older datasets retain their own source identities and adverse observations; they are not substituted for this matched final-runtime comparison.
|
|
197
197
|
|
|
@@ -24,7 +24,7 @@ The child starts at step zero and a new temporal origin. Its copied tail is pres
|
|
|
24
24
|
|
|
25
25
|
Initial copying requires a native fork start event, a regular canonical direct-parent session file, matching CWD/identity, a readable temporal source and an unused child namespace. Missing/unsafe evidence or CAS conflicts leave the copy unavailable rather than importing unrelated or newer private state. Explicit Start can retry an unaccepted copy in the same loaded fork after the cause is corrected.
|
|
26
26
|
|
|
27
|
-
Selecting a copied parent checkpoint through the child's `/tree` does not make it child-owned: State Flow stays disabled without resetting existing child data. Select a child-owned checkpoint or resume the original session. Cold recovery before the first child checkpoint, startup paths lacking the fork event, in-memory parent locators and cross-CWD imports remain outside this slice. File-only copying requires an exact still-available source cohort. See the [contract](fork-contract.md) and [SDK
|
|
27
|
+
Selecting a copied parent checkpoint through the child's `/tree` does not make it child-owned: State Flow stays disabled without resetting existing child data. Select a child-owned checkpoint or resume the original session. Cold recovery before the first child checkpoint, startup paths lacking the fork event, in-memory parent locators and cross-CWD imports remain outside this slice. File-only copying requires an exact still-available source cohort. See the [contract](fork-contract.md) and [SDK compatibility boundary](compatibility.md#public-host-seams); do not rewrite UUIDs or delete pointers to force recovery.
|
|
28
28
|
|
|
29
29
|
## Configuration
|
|
30
30
|
|
|
@@ -662,10 +662,10 @@ export default function stateFlowExtension(pi: ExtensionAPI, options: StateFlowE
|
|
|
662
662
|
pi.registerTool({
|
|
663
663
|
name: PATCH_STATE_TOOL_NAME,
|
|
664
664
|
label: "Patch State",
|
|
665
|
-
description: "The sole State Flow semantic mutation protocol. Supply any combination of global, cwd, and session patches; all supplied scopes commit atomically.
|
|
666
|
-
promptSnippet: "Atomically patch global/cwd/session; final:true
|
|
665
|
+
description: "The sole State Flow semantic mutation protocol. Supply any combination of global, cwd, and session patches; all supplied scopes commit atomically. In an active State Flow episode, set final:true when the current iteration may finish at a later turn_end; use {final:true} when no semantic update is needed. Passive turns have no terminal barrier: never call patch_state only to set final:true. This call must be the only State Flow barrier in its assistant response.",
|
|
666
|
+
promptSnippet: "Atomically patch global/cwd/session; active episodes use final:true before turn_end",
|
|
667
667
|
promptGuidelines: [
|
|
668
|
-
"Use patch_state for durable semantic changes.
|
|
668
|
+
"Use patch_state for durable semantic changes. Only in an active State Flow episode, make the iteration terminal-eligible before a final answer with final:true, optionally alongside atomic global/cwd/session patches. In passive mode, never call patch_state only to set final:true.",
|
|
669
669
|
"Use patch_state as reconciliation, not append-only notes: place new knowledge at the narrowest valid scope and remove superseded or completed state from touched branches.",
|
|
670
670
|
"Call patch_state alone in an assistant response; after its acknowledgement, further reasoning, tools, and later patch_state calls remain allowed.",
|
|
671
671
|
],
|
|
@@ -91,7 +91,7 @@ export function assistantToolCallCount(content: unknown): number {
|
|
|
91
91
|
return content.filter((block) => typeof block === "object" && block !== null && (block as { type?: unknown }).type === "toolCall").length;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/** The post-handler assistant
|
|
94
|
+
/** The accepted post-handler assistant text is authoritative. */
|
|
95
95
|
export function finalizedAssistantResponse(message: AgentMessage): string {
|
|
96
96
|
if (message.role !== "assistant" || !Array.isArray(message.content)) {
|
|
97
97
|
throw new Error("Finalized State Flow turn does not contain an assistant response");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-state-flow",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Incremental scoped state/context/memory compiler for Pi, inspired by SKILL.state",
|
|
6
6
|
"keywords": [
|
|
@@ -66,10 +66,10 @@
|
|
|
66
66
|
"node": ">=22.19.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@earendil-works/pi-agent-core": "
|
|
70
|
-
"@earendil-works/pi-ai": "
|
|
71
|
-
"@earendil-works/pi-coding-agent": "
|
|
72
|
-
"@earendil-works/pi-tui": "
|
|
69
|
+
"@earendil-works/pi-agent-core": ">=0.84.4",
|
|
70
|
+
"@earendil-works/pi-ai": ">=0.84.4",
|
|
71
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4",
|
|
72
|
+
"@earendil-works/pi-tui": ">=0.84.4"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@earendil-works/pi-tui": "0.84.4",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-kit",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@llblab/pi-clean-room": "0.1.1",
|
|
45
45
|
"@llblab/pi-codex-usage": "0.10.0",
|
|
46
46
|
"@llblab/pi-grow-loop": "0.8.1",
|
|
47
|
-
"@llblab/pi-state-flow": "0.16.
|
|
47
|
+
"@llblab/pi-state-flow": "0.16.3",
|
|
48
48
|
"@llblab/pi-telegram": "0.50.0",
|
|
49
49
|
"@llblab/skills": "1.15.0"
|
|
50
50
|
},
|