pi-fabric 0.103.1 → 0.104.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/README.md +7 -6
- package/dist/agents.js +3 -3
- package/dist/chunks/{chunk-GTRYXHRD.js → chunk-25LXRT3G.js} +4 -4
- package/dist/chunks/{chunk-CK3M6NTX.js → chunk-5LKJU6VU.js} +2 -2
- package/dist/chunks/{chunk-W63E3WEO.js → chunk-CXTTLBUV.js} +3 -2
- package/dist/chunks/chunk-CXTTLBUV.js.map +7 -0
- package/dist/chunks/{chunk-D7H5ZV7L.js → chunk-DRZDTBPZ.js} +8 -8
- package/dist/chunks/{chunk-OQIP5U4G.js → chunk-HTDX5H7Q.js} +10 -10
- package/dist/chunks/{chunk-O6VCKVCU.js → chunk-QABAX5PC.js} +4 -4
- package/dist/chunks/{chunk-CWVUV5YO.js → chunk-SV7ONATB.js} +2 -2
- package/dist/cli/decisions.js +2 -2
- package/dist/cli/mesh.js +3 -3
- package/dist/durable.d.ts +38 -0
- package/dist/durable.d.ts.map +1 -0
- package/dist/durable.js +274 -0
- package/dist/durable.js.map +7 -0
- package/dist/fabric-runtime-state.js +57 -57
- package/dist/index.js +119 -57
- package/dist/index.js.map +3 -3
- package/dist/jev/observation.js +3 -3
- package/dist/jev.js +4 -4
- package/dist/providers/jev-provider.js +4 -4
- package/dist/residency/host.js +5 -5
- package/dist/residency/pi-entry.js +5 -5
- package/dist/ui/controller.d.ts.map +1 -1
- package/dist/ui/conversation-chrome.d.ts +2 -0
- package/dist/ui/conversation-chrome.d.ts.map +1 -1
- package/dist/ui/conversation-chrome.js +1 -1
- package/dist/ui/conversation-latest.d.ts +10 -0
- package/dist/ui/conversation-latest.d.ts.map +1 -0
- package/dist/ui/conversation-scrollbar.d.ts +22 -0
- package/dist/ui/conversation-scrollbar.d.ts.map +1 -0
- package/dist/ui/conversation.d.ts +2 -0
- package/dist/ui/conversation.d.ts.map +1 -1
- package/dist/ui/conversation.js +228 -23
- package/dist/ui/conversation.js.map +4 -4
- package/dist/ui/dashboard.js +9 -9
- package/dist/ui/retention.d.ts +14 -0
- package/dist/ui/retention.d.ts.map +1 -0
- package/dist/ui/widget.d.ts +4 -2
- package/dist/ui/widget.d.ts.map +1 -1
- package/docs/agents.md +2 -0
- package/docs/durable-pi.md +186 -0
- package/docs/interface.md +3 -1
- package/package.json +17 -1
- package/dist/chunks/chunk-W63E3WEO.js.map +0 -7
- /package/dist/chunks/{chunk-GTRYXHRD.js.map → chunk-25LXRT3G.js.map} +0 -0
- /package/dist/chunks/{chunk-CK3M6NTX.js.map → chunk-5LKJU6VU.js.map} +0 -0
- /package/dist/chunks/{chunk-D7H5ZV7L.js.map → chunk-DRZDTBPZ.js.map} +0 -0
- /package/dist/chunks/{chunk-OQIP5U4G.js.map → chunk-HTDX5H7Q.js.map} +0 -0
- /package/dist/chunks/{chunk-O6VCKVCU.js.map → chunk-QABAX5PC.js.map} +0 -0
- /package/dist/chunks/{chunk-CWVUV5YO.js.map → chunk-SV7ONATB.js.map} +0 -0
package/README.md
CHANGED
|
@@ -102,8 +102,8 @@ pi install git:github.com/monotykamary/pi-fabric
|
|
|
102
102
|
From a local checkout:
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
bun install
|
|
106
|
+
bun run build
|
|
107
107
|
pi install /absolute/path/to/pi-fabric
|
|
108
108
|
```
|
|
109
109
|
|
|
@@ -160,6 +160,7 @@ See the [interface & commands reference](docs/interface.md) for every view, keyb
|
|
|
160
160
|
- [Execution kernels](docs/kernels.md): exclusive TypeScript/Python selection, Monty sandboxing, CPython escape hatch, agent inheritance, and examples.
|
|
161
161
|
- [Prompt cache](docs/prompt-cache.md): honest cache observations and optional, time-bounded native warming leases.
|
|
162
162
|
- [Thinking control](docs/thinking.md): scoped host-session reasoning effort with configured bounds that children inherit and never widen.
|
|
163
|
+
- [Optional durable Pi runner](docs/durable-pi.md): explicit hosted-backend registration, persistent submissions, recovery boundaries, and unchanged default runner behavior.
|
|
163
164
|
- [Durable decisions](docs/decisions.md): pending approvals and questions in the project mesh, headless approvals, routed child dialogs, `/fabric decisions`, and the `pi-fabric decisions` CLI.
|
|
164
165
|
- [Saved programs](docs/programs.md): content-addressed programs, nested `programs.run` with the caller's capabilities, `/fabric programs`, and host runs through `/fabric run` or an event.
|
|
165
166
|
- [Memory & recall](docs/memory-recall.md): compact ranked hits, uniform follow calls, lossless expansion, and guest-local `memory.walk` computation.
|
|
@@ -181,10 +182,10 @@ See the [interface & commands reference](docs/interface.md) for every view, keyb
|
|
|
181
182
|
## Development
|
|
182
183
|
|
|
183
184
|
```bash
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
bun install
|
|
186
|
+
bun run check:fast
|
|
187
|
+
bun run test:smoke
|
|
188
|
+
bun run build
|
|
188
189
|
```
|
|
189
190
|
|
|
190
191
|
The test suite covers:
|
package/dist/agents.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
validateAgentResult
|
|
3
|
-
} from "./chunks/chunk-3QECYQGA.js";
|
|
4
1
|
import {
|
|
5
2
|
AGENTS_ACTION_DESCRIPTORS,
|
|
6
3
|
normalizeAgentRunRequest
|
|
7
4
|
} from "./chunks/chunk-V7R3NVOS.js";
|
|
5
|
+
import {
|
|
6
|
+
validateAgentResult
|
|
7
|
+
} from "./chunks/chunk-3QECYQGA.js";
|
|
8
8
|
import {
|
|
9
9
|
AgentAdmission,
|
|
10
10
|
assertAgentTask,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
processSender
|
|
3
|
+
} from "./chunk-JKQARSWR.js";
|
|
1
4
|
import {
|
|
2
5
|
readJsonlPage
|
|
3
6
|
} from "./chunk-CGPK5WHX.js";
|
|
@@ -7,9 +10,6 @@ import {
|
|
|
7
10
|
lockOwnerLiveness,
|
|
8
11
|
writeFileAtomic
|
|
9
12
|
} from "./chunk-ITVLKXCI.js";
|
|
10
|
-
import {
|
|
11
|
-
processSender
|
|
12
|
-
} from "./chunk-JKQARSWR.js";
|
|
13
13
|
|
|
14
14
|
// src/mesh/store.ts
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
@@ -1326,4 +1326,4 @@ export {
|
|
|
1326
1326
|
MESH_MAX_SCHEDULE_AHEAD_MS,
|
|
1327
1327
|
MeshStore
|
|
1328
1328
|
};
|
|
1329
|
-
//# sourceMappingURL=chunk-
|
|
1329
|
+
//# sourceMappingURL=chunk-25LXRT3G.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
checkObserve,
|
|
7
7
|
jevObserveSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QABAX5PC.js";
|
|
9
9
|
import {
|
|
10
10
|
checkSchema,
|
|
11
11
|
checkValue,
|
|
@@ -512,4 +512,4 @@ export {
|
|
|
512
512
|
JEV_ACTION_DESCRIPTORS,
|
|
513
513
|
JevProvider
|
|
514
514
|
};
|
|
515
|
-
//# sourceMappingURL=chunk-
|
|
515
|
+
//# sourceMappingURL=chunk-5LKJU6VU.js.map
|
|
@@ -19,7 +19,8 @@ function readConversationAppearance(cwd, agentDir, projectTrusted) {
|
|
|
19
19
|
hideThinkingBlock: settings.getHideThinkingBlock(),
|
|
20
20
|
showImages: settings.getShowImages(),
|
|
21
21
|
imageWidthCells: settings.getImageWidthCells(),
|
|
22
|
-
copyOnSelect: settings.getFullscreenCopyOnSelect()
|
|
22
|
+
copyOnSelect: settings.getFullscreenCopyOnSelect(),
|
|
23
|
+
scrollbar: settings.getFullscreenScrollbar()
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
var footerPath = (cwd) => {
|
|
@@ -62,4 +63,4 @@ export {
|
|
|
62
63
|
readConversationAppearance,
|
|
63
64
|
conversationFooter
|
|
64
65
|
};
|
|
65
|
-
//# sourceMappingURL=chunk-
|
|
66
|
+
//# sourceMappingURL=chunk-CXTTLBUV.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ui/conversation-chrome.ts"],
|
|
4
|
+
"sourcesContent": ["import { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport type { ScrollViewScrollbar } from \"@earendil-works/pi-tui\";\nimport { getConversationHost } from \"./conversation-host.js\";\nimport { truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { formatTokens, safeText } from \"./format.js\";\nimport type { FabricConversationTarget } from \"./conversation.js\";\n\nexport interface FabricConversationAppearance {\n editorPaddingX: number;\n outputPad: 0 | 1;\n codeBlockIndent?: string;\n hideThinkingBlock?: boolean;\n showImages?: boolean;\n imageWidthCells?: number;\n copyOnSelect?: boolean;\n scrollbar?: ScrollViewScrollbar;\n}\n\n/** Read the host's public Pi settings without changing its editor or footer. */\nexport function readConversationAppearance(cwd: string, agentDir: string, projectTrusted: boolean): FabricConversationAppearance {\n const settings = getConversationHost().SettingsManager.create(cwd, agentDir, { projectTrusted });\n return {\n editorPaddingX: settings.getEditorPaddingX(), outputPad: settings.getOutputPad(),\n codeBlockIndent: settings.getCodeBlockIndent(), hideThinkingBlock: settings.getHideThinkingBlock(),\n showImages: settings.getShowImages(), imageWidthCells: settings.getImageWidthCells(),\n copyOnSelect: settings.getFullscreenCopyOnSelect(),\n scrollbar: settings.getFullscreenScrollbar(),\n };\n}\n\nconst footerPath = (cwd: string): string => {\n const home = homedir();\n if (cwd === home) return \"~\";\n return cwd.startsWith(`${home}${path.sep}`) ? `~${cwd.slice(home.length)}` : cwd;\n};\n\n/** Native-shaped footer backed by this participant, never by Main's session stats. */\nexport function conversationFooter(target: FabricConversationTarget | undefined, theme: Theme, width: number): string[] {\n if (!target || width <= 0) return [];\n const location = target.cwd ? footerPath(target.cwd) : \"cwd unavailable\";\n const branch = target.branch ? ` (${target.branch})` : \"\";\n const pwd = safeText(`${location}${branch} \u2022 ${target.name}`);\n const access = target.readOnlyReason ? theme.fg(\"warning\", \"read-only\") : \"\";\n const separator = theme.fg(\"dim\", \" \u2022 \");\n const locationWidth = width - (access ? visibleWidth(separator) + visibleWidth(access) : 0);\n const pathLine = locationWidth > 0\n ? theme.fg(\"dim\", truncateToWidth(pwd, locationWidth, \"\u2026\")) + (access ? separator + access : \"\")\n : truncateToWidth(access, width, \"\u2026\");\n const stats = [safeText(target.status)];\n if (target.usage) {\n const usage = target.usage;\n // Agent usage is run-scoped; actor values describe the current/last activation.\n stats.push(\"run\", `\u2191${formatTokens(usage.input)}`, `\u2193${formatTokens(usage.output)}`);\n if (usage.cacheRead > 0) stats.push(`R${formatTokens(usage.cacheRead)}`);\n if (usage.cacheWrite > 0) stats.push(`W${formatTokens(usage.cacheWrite)}`);\n if (Number.isFinite(usage.cost)) stats.push(`$${usage.cost.toFixed(3)}`);\n } else {\n stats.push(\"usage unavailable\");\n }\n // Cumulative run tokens are not current context occupancy. Do not invent a percentage.\n stats.push(target.contextWindow ? `?/${formatTokens(target.contextWindow)} ctx` : \"ctx ?\");\n const model = safeText(target.model ?? `${target.runner ?? \"\"} model unavailable`).trim();\n const thinking = target.thinking ? ` \u2022 ${safeText(target.thinking === \"off\" ? \"thinking off\" : target.thinking)}` : \"\";\n const left = truncateToWidth(stats.join(\" \"), width, \"\u2026\");\n const right = truncateToWidth(`${model}${thinking}`, Math.max(0, width - visibleWidth(left) - 2), \"\");\n const gap = \" \".repeat(Math.max(0, width - visibleWidth(left) - visibleWidth(right)));\n return [\n pathLine,\n theme.fg(\"dim\", `${left}${gap}${right}`),\n ];\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -19,6 +19,13 @@ import {
|
|
|
19
19
|
isInside,
|
|
20
20
|
readWritePolicy
|
|
21
21
|
} from "./chunk-2USMWEE6.js";
|
|
22
|
+
import {
|
|
23
|
+
launchScope,
|
|
24
|
+
normalizeScope,
|
|
25
|
+
processSender,
|
|
26
|
+
senderStamp,
|
|
27
|
+
senderTrusted
|
|
28
|
+
} from "./chunk-JKQARSWR.js";
|
|
22
29
|
import {
|
|
23
30
|
peerLabelPrefix,
|
|
24
31
|
readChildToolAllowlist
|
|
@@ -82,13 +89,6 @@ import {
|
|
|
82
89
|
isFabricRunnerId,
|
|
83
90
|
requireAgentRunner
|
|
84
91
|
} from "./chunk-4RTHQGES.js";
|
|
85
|
-
import {
|
|
86
|
-
launchScope,
|
|
87
|
-
normalizeScope,
|
|
88
|
-
processSender,
|
|
89
|
-
senderStamp,
|
|
90
|
-
senderTrusted
|
|
91
|
-
} from "./chunk-JKQARSWR.js";
|
|
92
92
|
|
|
93
93
|
// src/core/model-usage.ts
|
|
94
94
|
import { readFileSync } from "node:fs";
|
|
@@ -7743,4 +7743,4 @@ export {
|
|
|
7743
7743
|
agentParticipantRecords,
|
|
7744
7744
|
actorParticipantRecord
|
|
7745
7745
|
};
|
|
7746
|
-
//# sourceMappingURL=chunk-
|
|
7746
|
+
//# sourceMappingURL=chunk-DRZDTBPZ.js.map
|
|
@@ -8,25 +8,28 @@ import {
|
|
|
8
8
|
agentParticipantRecords,
|
|
9
9
|
loadModelUsage,
|
|
10
10
|
useBudgetLedger
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DRZDTBPZ.js";
|
|
12
12
|
import {
|
|
13
13
|
MeshStore
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-25LXRT3G.js";
|
|
15
|
+
import {
|
|
16
|
+
launchScope
|
|
17
|
+
} from "./chunk-JKQARSWR.js";
|
|
15
18
|
import {
|
|
16
19
|
RESIDENT_HOST_FORMAT,
|
|
17
20
|
residentDeliveryPrefix,
|
|
18
21
|
residentHostId
|
|
19
22
|
} from "./chunk-NTC2MCB6.js";
|
|
23
|
+
import {
|
|
24
|
+
parseFabricOwnedModelGuidance,
|
|
25
|
+
resolveFabricModelGuidance
|
|
26
|
+
} from "./chunk-UKMQK5VP.js";
|
|
20
27
|
import {
|
|
21
28
|
ownerHeartbeatFields,
|
|
22
29
|
recordOwnerLiveness,
|
|
23
30
|
startOwnerHeartbeat,
|
|
24
31
|
writeJsonAtomic
|
|
25
32
|
} from "./chunk-ITVLKXCI.js";
|
|
26
|
-
import {
|
|
27
|
-
parseFabricOwnedModelGuidance,
|
|
28
|
-
resolveFabricModelGuidance
|
|
29
|
-
} from "./chunk-UKMQK5VP.js";
|
|
30
33
|
import {
|
|
31
34
|
lifecycleSourceIdentity
|
|
32
35
|
} from "./chunk-KJZAOENY.js";
|
|
@@ -34,9 +37,6 @@ import {
|
|
|
34
37
|
normalizeModelAliases,
|
|
35
38
|
resolveAvailablePiModel
|
|
36
39
|
} from "./chunk-ZLNJDTCN.js";
|
|
37
|
-
import {
|
|
38
|
-
launchScope
|
|
39
|
-
} from "./chunk-JKQARSWR.js";
|
|
40
40
|
|
|
41
41
|
// src/residency/host.ts
|
|
42
42
|
import { randomUUID } from "node:crypto";
|
|
@@ -815,4 +815,4 @@ export {
|
|
|
815
815
|
residentIdleDecision,
|
|
816
816
|
runResidentHostFromConfigPath
|
|
817
817
|
};
|
|
818
|
-
//# sourceMappingURL=chunk-
|
|
818
|
+
//# sourceMappingURL=chunk-HTDX5H7Q.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
object
|
|
3
|
-
} from "./chunk-WHBJDTCR.js";
|
|
4
1
|
import {
|
|
5
2
|
prepareFabricActorHostPayload
|
|
6
3
|
} from "./chunk-CGL7QP4A.js";
|
|
4
|
+
import {
|
|
5
|
+
object
|
|
6
|
+
} from "./chunk-WHBJDTCR.js";
|
|
7
7
|
import {
|
|
8
8
|
validationMessage
|
|
9
9
|
} from "./chunk-SS7FVARK.js";
|
|
@@ -283,4 +283,4 @@ export {
|
|
|
283
283
|
JevObservationHost,
|
|
284
284
|
JevSubscription
|
|
285
285
|
};
|
|
286
|
-
//# sourceMappingURL=chunk-
|
|
286
|
+
//# sourceMappingURL=chunk-QABAX5PC.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
validateMeshTopic
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-25LXRT3G.js";
|
|
4
4
|
import {
|
|
5
5
|
writeFileAtomic
|
|
6
6
|
} from "./chunk-ITVLKXCI.js";
|
|
@@ -232,4 +232,4 @@ export {
|
|
|
232
232
|
meshPostCommand,
|
|
233
233
|
wrapDurableNotifyScript
|
|
234
234
|
};
|
|
235
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-SV7ONATB.js.map
|
package/dist/cli/decisions.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "../chunks/chunk-FSB2VIRZ.js";
|
|
5
5
|
import {
|
|
6
6
|
MeshStore
|
|
7
|
-
} from "../chunks/chunk-
|
|
7
|
+
} from "../chunks/chunk-25LXRT3G.js";
|
|
8
|
+
import "../chunks/chunk-JKQARSWR.js";
|
|
8
9
|
import "../chunks/chunk-CGPK5WHX.js";
|
|
9
10
|
import "../chunks/chunk-ITVLKXCI.js";
|
|
10
|
-
import "../chunks/chunk-JKQARSWR.js";
|
|
11
11
|
|
|
12
12
|
// src/cli/decisions.ts
|
|
13
13
|
import fs from "node:fs";
|
package/dist/cli/mesh.js
CHANGED
|
@@ -2,13 +2,13 @@ import {
|
|
|
2
2
|
MESH_EXTERNAL_DATA_MAX_BYTES,
|
|
3
3
|
MESH_GRANT_TOKEN_ENV,
|
|
4
4
|
postWithMeshGrant
|
|
5
|
-
} from "../chunks/chunk-
|
|
5
|
+
} from "../chunks/chunk-SV7ONATB.js";
|
|
6
6
|
import {
|
|
7
7
|
MeshStore
|
|
8
|
-
} from "../chunks/chunk-
|
|
8
|
+
} from "../chunks/chunk-25LXRT3G.js";
|
|
9
|
+
import "../chunks/chunk-JKQARSWR.js";
|
|
9
10
|
import "../chunks/chunk-CGPK5WHX.js";
|
|
10
11
|
import "../chunks/chunk-ITVLKXCI.js";
|
|
11
|
-
import "../chunks/chunk-JKQARSWR.js";
|
|
12
12
|
|
|
13
13
|
// src/cli/mesh.ts
|
|
14
14
|
import fs from "node:fs";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { HarnessOptions, ModelRef, Registry, Storage } from "@earendil-works/pi-durable";
|
|
2
|
+
import type { FabricHostedRunner } from "./agents/runner-registry.js";
|
|
3
|
+
/** The host must hold exclusive ownership until release, including across processes. */
|
|
4
|
+
export interface PiDurableStorageLease {
|
|
5
|
+
storage: Storage;
|
|
6
|
+
release(): void | Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export type PiDurableStorageOptions = {
|
|
9
|
+
kind: "jsonl";
|
|
10
|
+
directory: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "factory";
|
|
13
|
+
identity: string;
|
|
14
|
+
acquire(runId: string): Promise<PiDurableStorageLease>;
|
|
15
|
+
};
|
|
16
|
+
export interface PiDurableRunnerOptions {
|
|
17
|
+
id?: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
residentModule?: string;
|
|
20
|
+
models: HarnessOptions["models"];
|
|
21
|
+
registry: Registry;
|
|
22
|
+
env: NonNullable<HarnessOptions["env"]>;
|
|
23
|
+
allowedModels: readonly ModelRef[];
|
|
24
|
+
storage: PiDurableStorageOptions;
|
|
25
|
+
}
|
|
26
|
+
export interface PiDurableRunner extends FabricHostedRunner {
|
|
27
|
+
/** Seal this instance, join invocations and release storage; never abort work. Create a new runner to reopen. */
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export interface PiDurableLocator {
|
|
31
|
+
version: 1;
|
|
32
|
+
backend: "pi-durable";
|
|
33
|
+
storage: string;
|
|
34
|
+
runId: string;
|
|
35
|
+
}
|
|
36
|
+
/** Opt-in hosted adapter. No registration or runtime package loading occurs at factory creation. */
|
|
37
|
+
export declare function createPiDurableRunner(options: PiDurableRunnerOptions): PiDurableRunner;
|
|
38
|
+
//# sourceMappingURL=durable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["../src/durable.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAW,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAmF,MAAM,4BAA4B,CAAC;AACxL,OAAO,KAAK,EAAE,kBAAkB,EAAsE,MAAM,6BAA6B,CAAC;AAG1I,wFAAwF;AACxF,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AACD,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;CAAE,CAAC;AAClG,MAAM,WAAW,sBAAsB;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,EAAE,WAAW,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC,aAAa,EAAE,SAAS,QAAQ,EAAE,CAAC;IACnC,OAAO,EAAE,uBAAuB,CAAC;CAClC;AACD,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,iHAAiH;IACjH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AACD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAmCD,oGAAoG;AACpG,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAmNtF"}
|
package/dist/durable.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
// src/durable.ts
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
var runtimePromise;
|
|
7
|
+
async function runtime() {
|
|
8
|
+
return runtimePromise ??= Promise.resolve().then(() => {
|
|
9
|
+
const require2 = createRequire(import.meta.url);
|
|
10
|
+
for (const name of ["@earendil-works/pi-durable", "@earendil-works/chord"]) {
|
|
11
|
+
const metadata = require2(`${name}/package.json`);
|
|
12
|
+
if (metadata.version !== "1.0.0") throw new Error(`Unsupported ${name} version ${metadata.version ?? "unknown"}; expected 1.0.0`);
|
|
13
|
+
}
|
|
14
|
+
return Promise.all([import("@earendil-works/pi-durable"), import("@earendil-works/chord/context")]);
|
|
15
|
+
}).then(([durable, context]) => ({ durable, context })).catch((cause) => {
|
|
16
|
+
runtimePromise = void 0;
|
|
17
|
+
throw new Error(`Pi durable runner requires optional peers @earendil-works/pi-durable@1.0.0 and @earendil-works/chord@1.0.0: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
var hash = (value) => createHash("sha256").update(value).digest("hex");
|
|
21
|
+
var ownershipSymbol = Symbol.for("pi-fabric.durable.owners.v1");
|
|
22
|
+
var globals = globalThis;
|
|
23
|
+
var owners = globals[ownershipSymbol] ??= /* @__PURE__ */ new Set();
|
|
24
|
+
function createPiDurableRunner(options) {
|
|
25
|
+
if (!options.models || !options.registry || typeof options.env !== "function") throw new Error("Pi durable requires host models, registry and environment");
|
|
26
|
+
const storage = options.storage;
|
|
27
|
+
const directory = storage.kind === "jsonl" ? path.resolve(storage.directory) : void 0;
|
|
28
|
+
if (storage.kind === "factory" && (!storage.identity || typeof storage.acquire !== "function")) throw new Error("Storage factory requires identity and exclusive acquire()");
|
|
29
|
+
const identity = hash(storage.kind === "jsonl" ? `jsonl:${directory}` : `factory:${storage.identity}`);
|
|
30
|
+
const allowed = new Map(options.allowedModels.map((model) => [`${model.provider}/${model.modelId}`, { ...model }]));
|
|
31
|
+
if (!allowed.size) throw new Error("Pi durable requires an explicit model allowlist");
|
|
32
|
+
const runs = /* @__PURE__ */ new Map();
|
|
33
|
+
const transcriptSeen = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
let sealed = false;
|
|
35
|
+
let tail = Promise.resolve();
|
|
36
|
+
let closing;
|
|
37
|
+
const serial = (fn) => {
|
|
38
|
+
if (sealed) return Promise.reject(new Error("Pi durable runner is closed"));
|
|
39
|
+
const result = tail.then(fn);
|
|
40
|
+
tail = result.catch(() => void 0);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
function locator(value) {
|
|
44
|
+
const loc = value;
|
|
45
|
+
if (!loc || loc.version !== 1 || loc.backend !== "pi-durable" || loc.storage !== identity || typeof loc.runId !== "string" || !loc.runId || loc.runId.length > 512) throw new Error("Invalid Pi durable locator or storage identity");
|
|
46
|
+
return loc;
|
|
47
|
+
}
|
|
48
|
+
function validate(context) {
|
|
49
|
+
if (context.id !== context.idempotencyKey) throw new Error("Pi durable requires Fabric run ID as idempotencyKey");
|
|
50
|
+
if (context.residency === "durable" && !options.residentModule) throw new Error("Durable residency requires an explicit residentModule");
|
|
51
|
+
for (const key of ["kernel", "sessionFile", "actorId", "actorName", "writePolicy", "scope", "schema"]) {
|
|
52
|
+
if (context[key] !== void 0) throw new Error(`Pi durable does not support ${key}`);
|
|
53
|
+
}
|
|
54
|
+
if (context.recursive || context.images?.length) throw new Error("Pi durable does not support recursiveFabric or image input");
|
|
55
|
+
const model = context.model ? allowed.get(context.model) : void 0;
|
|
56
|
+
if (!model || !options.models.getModel(model.provider, model.modelId)) throw new Error(`Unknown or disallowed Pi durable model: ${context.model ?? "(missing explicit provider/model)"}`);
|
|
57
|
+
const catalogModel = options.models.getModel(model.provider, model.modelId);
|
|
58
|
+
if (context.thinking && (!catalogModel.reasoning && context.thinking !== "off" || catalogModel.thinkingLevelMap?.[context.thinking] === null)) throw new Error(`Unsupported thinking level: ${context.thinking}`);
|
|
59
|
+
const snapshot = options.registry.snapshot();
|
|
60
|
+
const available = new Map(snapshot.tools().map(({ tool }) => [tool.name, tool]));
|
|
61
|
+
const tools = context.tools.map((name) => {
|
|
62
|
+
let tool = available.get(name);
|
|
63
|
+
if (!tool) throw new Error(`Unknown Pi durable tool: ${name}`);
|
|
64
|
+
for (const extension of snapshot.installed()) for (const wrap of extension.wraps ?? []) {
|
|
65
|
+
if ("tool" in wrap && wrap.tool === name) tool = wrap.wrap(tool);
|
|
66
|
+
}
|
|
67
|
+
if (tool.name !== name) throw new Error(`Registry wrapper renamed tool ${name}`);
|
|
68
|
+
const implementation = tool;
|
|
69
|
+
return { ...implementation, replay: name === "fabric_exec" ? "unsafe" : implementation.replay ?? "unsafe", execute: async (...args) => {
|
|
70
|
+
const result = await implementation.execute(...args);
|
|
71
|
+
if (result.control?.addTools || result.control?.handoff) throw new Error("Pi durable adapter does not support tool-set changes or handoff controls");
|
|
72
|
+
return result;
|
|
73
|
+
} };
|
|
74
|
+
});
|
|
75
|
+
const fingerprint = hash(JSON.stringify({ task: context.task, cwd: context.cwd, model, tools: [...context.tools], thinking: context.thinking ?? "off", systemPrompt: context.systemPrompt ?? "" }));
|
|
76
|
+
return { model, tools, fingerprint };
|
|
77
|
+
}
|
|
78
|
+
async function acquire(runId, rt) {
|
|
79
|
+
if (storage.kind === "factory") return storage.acquire(runId);
|
|
80
|
+
const base = directory;
|
|
81
|
+
await fs.mkdir(base, { recursive: true });
|
|
82
|
+
const canonical = await fs.realpath(base);
|
|
83
|
+
const stem = hash(runId);
|
|
84
|
+
const lock = path.join(canonical, `${stem}.writer`);
|
|
85
|
+
try {
|
|
86
|
+
await fs.mkdir(lock);
|
|
87
|
+
} catch (cause) {
|
|
88
|
+
throw new Error(`Pi durable single-writer lock unavailable: ${lock}. Never remove a stale lock until its owner is verified dead.`, { cause });
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const { openNodeJsonlStorage } = await import("@earendil-works/pi-durable/storage/jsonl/node");
|
|
92
|
+
const opened = await openNodeJsonlStorage(path.join(canonical, stem), rt.context.BACKGROUND_CONTEXT, { fsync: true });
|
|
93
|
+
return { storage: opened, release: () => fs.rmdir(lock) };
|
|
94
|
+
} catch (error) {
|
|
95
|
+
await fs.rmdir(lock);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function open(runId, selected) {
|
|
100
|
+
const existing = runs.get(runId);
|
|
101
|
+
if (existing) {
|
|
102
|
+
if (existing.fingerprint && existing.fingerprint !== selected.fingerprint) throw new Error("Fabric run ID already bound to different work");
|
|
103
|
+
return existing;
|
|
104
|
+
}
|
|
105
|
+
const ownerKey = `${identity}:${runId}`;
|
|
106
|
+
if (owners.has(ownerKey)) throw new Error("Pi durable storage already has an active writer");
|
|
107
|
+
owners.add(ownerKey);
|
|
108
|
+
let lease;
|
|
109
|
+
try {
|
|
110
|
+
const rt = await runtime();
|
|
111
|
+
lease = await acquire(runId, rt);
|
|
112
|
+
const registry = rt.durable.createRegistry();
|
|
113
|
+
registry.install(rt.durable.defineExtension({ name: "fabric.durable.tools", tools: selected.tools }));
|
|
114
|
+
const harness = await rt.durable.Harness.open(lease.storage, { models: options.models, registry, env: options.env, settings: { compaction: { enabled: false }, retry: { enabled: false }, stream: { maxRetries: 0 } } }, rt.context.BACKGROUND_CONTEXT);
|
|
115
|
+
const run = { harness, lease, ownerKey, reporters: /* @__PURE__ */ new Set() };
|
|
116
|
+
runs.set(runId, run);
|
|
117
|
+
return run;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (lease) {
|
|
120
|
+
try {
|
|
121
|
+
await lease.storage.close((await runtime()).context.BACKGROUND_CONTEXT);
|
|
122
|
+
await lease.release();
|
|
123
|
+
} catch (cleanupError) {
|
|
124
|
+
throw new AggregateError([error, cleanupError], "Pi durable open failed; cleanup failed, lease remains owned");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
owners.delete(ownerKey);
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function bind(value, context, reporter, admit) {
|
|
132
|
+
const loc = locator(value);
|
|
133
|
+
if (loc.runId !== context.id) throw new Error("Pi durable locator does not match Fabric run ID");
|
|
134
|
+
const selected = validate(context);
|
|
135
|
+
const rt = await runtime();
|
|
136
|
+
const { getSupportedThinkingLevels } = await import("@earendil-works/pi-ai/models");
|
|
137
|
+
if (!getSupportedThinkingLevels(options.models.getModel(selected.model.provider, selected.model.modelId)).includes(context.thinking ?? "off")) throw new Error(`Unsupported thinking level: ${context.thinking ?? "off"}`);
|
|
138
|
+
const ctx = rt.context.BACKGROUND_CONTEXT;
|
|
139
|
+
const run = await open(loc.runId, selected);
|
|
140
|
+
const Manifest = rt.durable.defineDoc({ kind: "fabric.durable.request", version: 1, scope: "conversation", history: "latest", fork: "initial", initial: () => ({ fingerprint: selected.fingerprint }) });
|
|
141
|
+
let conversation = await run.harness.conversation(rt.durable.ROOT_CONVERSATION_ID, ctx);
|
|
142
|
+
if (!conversation && admit) conversation = await run.harness.root(ctx, { agent: { model: selected.model, tools: selected.tools, thinkingLevel: context.thinking ?? "off", cwd: context.cwd, instructions: context.systemPrompt ?? "" }, init: async (tx, id) => {
|
|
143
|
+
await tx.doc(Manifest, id);
|
|
144
|
+
} });
|
|
145
|
+
if (!conversation) throw new Error("Pi durable attach found no existing conversation; outcome indeterminate (not resubmitted)");
|
|
146
|
+
const manifest = await run.harness.snapshot(Manifest, conversation.id, ctx);
|
|
147
|
+
if (manifest?.fingerprint !== selected.fingerprint) throw new Error("Fabric run ID already bound to different work or missing committed manifest");
|
|
148
|
+
run.fingerprint = selected.fingerprint;
|
|
149
|
+
run.conversation = conversation;
|
|
150
|
+
const found = await conversation.commit((tx) => tx.submissionByRequest(conversation.id, context.id), ctx);
|
|
151
|
+
let submission = found ? await run.harness.submission(found.id, ctx) : void 0;
|
|
152
|
+
if (!submission && admit) submission = await conversation.submit({ type: "input", content: context.task, requestId: context.id }, ctx);
|
|
153
|
+
if (!submission) throw new Error("Pi durable attach found no existing submission; outcome indeterminate (not resubmitted)");
|
|
154
|
+
run.submission = submission;
|
|
155
|
+
run.reporters.add(reporter);
|
|
156
|
+
if (!run.watch) {
|
|
157
|
+
run.watch = await conversation.watch(ctx);
|
|
158
|
+
run.watch.start(async (view) => {
|
|
159
|
+
for (const target of run.reporters) report(view, target);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
report(run.watch.value, reporter);
|
|
163
|
+
if (!run.observing) {
|
|
164
|
+
run.observing = submission.wait(ctx).then(async (result) => {
|
|
165
|
+
if (sealed) return;
|
|
166
|
+
const view = await conversation.context(ctx);
|
|
167
|
+
const answer = result.type === "input" && result.status === "done" ? view.entries.find((entry) => entry.id === result.answer) : void 0;
|
|
168
|
+
const output = answer?.model?.flatMap((message) => message.role === "assistant" ? message.content.filter((block) => block.type === "text").map((block) => block.text) : []).join("") ?? "";
|
|
169
|
+
const usage = await run.harness.usage(ctx);
|
|
170
|
+
for (const target of run.reporters) {
|
|
171
|
+
target.usage(totalUsage(usage));
|
|
172
|
+
target.finish({ status: result.status === "done" ? "completed" : result.reason === "aborted" ? "stopped" : "failed", output: result.status === "done" ? output : `Pi durable unanswered: ${result.reason}` });
|
|
173
|
+
}
|
|
174
|
+
delete run.observing;
|
|
175
|
+
}).catch((error) => {
|
|
176
|
+
if (!sealed) for (const target of run.reporters) target.fail({ error: `Pi durable observation failed: ${String(error)}` });
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function totalUsage(usage) {
|
|
181
|
+
const total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
|
|
182
|
+
for (const bucket of [usage.models, usage.tools]) for (const item of Object.values(bucket)) {
|
|
183
|
+
total.input += item.input;
|
|
184
|
+
total.output += item.output;
|
|
185
|
+
total.cacheRead += item.cacheRead;
|
|
186
|
+
total.cacheWrite += item.cacheWrite;
|
|
187
|
+
total.cost += item.cost.total;
|
|
188
|
+
}
|
|
189
|
+
return total;
|
|
190
|
+
}
|
|
191
|
+
function report(view, reporter) {
|
|
192
|
+
let seen = transcriptSeen.get(reporter);
|
|
193
|
+
if (!seen) {
|
|
194
|
+
seen = /* @__PURE__ */ new Set();
|
|
195
|
+
transcriptSeen.set(reporter, seen);
|
|
196
|
+
}
|
|
197
|
+
for (const entry of view.entries) {
|
|
198
|
+
if (seen.has(entry.id)) continue;
|
|
199
|
+
seen.add(entry.id);
|
|
200
|
+
for (const message of entry.model ?? []) {
|
|
201
|
+
if (message.role === "assistant" || message.role === "user") {
|
|
202
|
+
const content = typeof message.content === "string" ? message.content : message.content.filter((block) => block.type === "text").map((block) => ({ type: "text", text: block.text }));
|
|
203
|
+
reporter.transcript({ type: "message_end", message: { role: message.role, content } });
|
|
204
|
+
if (message.role === "assistant") {
|
|
205
|
+
for (const block of message.content) if (block.type === "toolCall") reporter.transcript({ type: "tool_execution_start", toolCallId: block.id, toolName: block.name, args: block.arguments });
|
|
206
|
+
}
|
|
207
|
+
} else if (message.role === "toolResult") reporter.transcript({ type: "tool_execution_end", toolCallId: message.toolCallId, toolName: message.toolName, result: message.content, isError: message.isError });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const assistants = view.entries.flatMap((entry) => entry.model?.filter((message) => message.role === "assistant") ?? []);
|
|
211
|
+
const live = view.docs["pi.live"];
|
|
212
|
+
const last = live?.generation?.message ?? assistants.at(-1);
|
|
213
|
+
const calls = assistants.flatMap((message) => message.role === "assistant" ? message.content.filter((block) => block.type === "toolCall") : []);
|
|
214
|
+
reporter.progress({ turns: assistants.length, toolCalls: calls.length, currentTool: live?.tools?.find((tool) => tool.status === "running")?.name ?? null, text: last?.role === "assistant" ? last.content.filter((block) => block.type === "text").map((block) => block.text).join("") : "" });
|
|
215
|
+
const usage = view.docs["pi.usage"];
|
|
216
|
+
if (usage) reporter.usage(totalUsage(usage));
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
id: options.id ?? "pi-durable",
|
|
220
|
+
label: options.label ?? "Pi durable (opt-in)",
|
|
221
|
+
kind: "hosted",
|
|
222
|
+
...options.residentModule ? { residentModule: options.residentModule } : {},
|
|
223
|
+
capabilities: Object.freeze({ recursiveFabric: false, steer: false, followUp: false, persistentSessions: false, kernels: false, handoff: false, modelDiscovery: false, imageInput: false, compaction: false, questions: false, sleep: false, writePolicy: false }),
|
|
224
|
+
prepare(context) {
|
|
225
|
+
if (sealed) throw new Error("Pi durable runner is closed");
|
|
226
|
+
validate(context);
|
|
227
|
+
return { version: 1, backend: "pi-durable", storage: identity, runId: context.id };
|
|
228
|
+
},
|
|
229
|
+
normalizeModel(model) {
|
|
230
|
+
if (!allowed.has(model)) throw new Error(`Unknown or disallowed Pi durable model: ${model}`);
|
|
231
|
+
return model;
|
|
232
|
+
},
|
|
233
|
+
mapTools(tools) {
|
|
234
|
+
const names = new Set(options.registry.snapshot().tools().map((item) => item.tool.name));
|
|
235
|
+
for (const tool of tools) if (!names.has(tool)) throw new Error(`Unknown Pi durable tool: ${tool}`);
|
|
236
|
+
return [...tools];
|
|
237
|
+
},
|
|
238
|
+
start: (loc, context, reporter) => serial(() => bind(loc, context, reporter, true)),
|
|
239
|
+
attach: (loc, context, reporter) => serial(() => bind(loc, context, reporter, false)),
|
|
240
|
+
liveness: (value) => serial(async () => {
|
|
241
|
+
const run = runs.get(locator(value).runId);
|
|
242
|
+
if (!run?.submission) return "unknown";
|
|
243
|
+
const result = await run.submission.status((await runtime()).context.BACKGROUND_CONTEXT);
|
|
244
|
+
return result.status === "done" ? "settled" : result.status === "unanswered" ? result.reason === "aborted" ? "cancelled" : "interrupted" : "running";
|
|
245
|
+
}),
|
|
246
|
+
stop: (value) => serial(async () => {
|
|
247
|
+
const run = runs.get(locator(value).runId);
|
|
248
|
+
if (!run?.conversation || !run.submission) return { confirmed: false };
|
|
249
|
+
await run.conversation.abort((await runtime()).context.BACKGROUND_CONTEXT, { background: true });
|
|
250
|
+
return { confirmed: true };
|
|
251
|
+
}),
|
|
252
|
+
close() {
|
|
253
|
+
if (closing) return closing;
|
|
254
|
+
sealed = true;
|
|
255
|
+
closing = tail.then(async () => {
|
|
256
|
+
const results = await Promise.allSettled([...runs].map(async ([id, run]) => {
|
|
257
|
+
await run.watch?.stop();
|
|
258
|
+
await run.harness.close((await runtime()).context.BACKGROUND_CONTEXT);
|
|
259
|
+
await run.observing;
|
|
260
|
+
await run.lease.release();
|
|
261
|
+
owners.delete(run.ownerKey);
|
|
262
|
+
runs.delete(id);
|
|
263
|
+
}));
|
|
264
|
+
const failed = results.filter((result) => result.status === "rejected");
|
|
265
|
+
if (failed.length) throw new AggregateError(failed.map((result) => result.reason), "Pi durable close failed; failed leases remain owned");
|
|
266
|
+
});
|
|
267
|
+
return closing;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
export {
|
|
272
|
+
createPiDurableRunner
|
|
273
|
+
};
|
|
274
|
+
//# sourceMappingURL=durable.js.map
|