@aigne/agent-runtime 1.12.0-beta.5
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/LICENSE.md +26 -0
- package/README.md +79 -0
- package/dist/agent-runners/ai-runner.cjs +133 -0
- package/dist/agent-runners/ai-runner.d.cts +33 -0
- package/dist/agent-runners/ai-runner.d.cts.map +1 -0
- package/dist/agent-runners/ai-runner.d.mts +33 -0
- package/dist/agent-runners/ai-runner.d.mts.map +1 -0
- package/dist/agent-runners/ai-runner.mjs +134 -0
- package/dist/agent-runners/ai-runner.mjs.map +1 -0
- package/dist/agent-runners/ash-runner.cjs +272 -0
- package/dist/agent-runners/ash-runner.d.cts +30 -0
- package/dist/agent-runners/ash-runner.d.cts.map +1 -0
- package/dist/agent-runners/ash-runner.d.mts +30 -0
- package/dist/agent-runners/ash-runner.d.mts.map +1 -0
- package/dist/agent-runners/ash-runner.mjs +273 -0
- package/dist/agent-runners/ash-runner.mjs.map +1 -0
- package/dist/agent-runners/budget.cjs +71 -0
- package/dist/agent-runners/budget.d.cts +40 -0
- package/dist/agent-runners/budget.d.cts.map +1 -0
- package/dist/agent-runners/budget.d.mts +40 -0
- package/dist/agent-runners/budget.d.mts.map +1 -0
- package/dist/agent-runners/budget.mjs +67 -0
- package/dist/agent-runners/budget.mjs.map +1 -0
- package/dist/agent-runners/code-runner.cjs +61 -0
- package/dist/agent-runners/code-runner.mjs +61 -0
- package/dist/agent-runners/code-runner.mjs.map +1 -0
- package/dist/agent-runners/env-whitelist.cjs +36 -0
- package/dist/agent-runners/env-whitelist.d.cts +5 -0
- package/dist/agent-runners/env-whitelist.d.cts.map +1 -0
- package/dist/agent-runners/env-whitelist.d.mts +5 -0
- package/dist/agent-runners/env-whitelist.d.mts.map +1 -0
- package/dist/agent-runners/env-whitelist.mjs +36 -0
- package/dist/agent-runners/env-whitelist.mjs.map +1 -0
- package/dist/agent-runners/guide-rails.cjs +47 -0
- package/dist/agent-runners/guide-rails.d.cts +16 -0
- package/dist/agent-runners/guide-rails.d.cts.map +1 -0
- package/dist/agent-runners/guide-rails.d.mts +16 -0
- package/dist/agent-runners/guide-rails.d.mts.map +1 -0
- package/dist/agent-runners/guide-rails.mjs +48 -0
- package/dist/agent-runners/guide-rails.mjs.map +1 -0
- package/dist/agent-runners/hook-channel.cjs +55 -0
- package/dist/agent-runners/hook-channel.d.cts +38 -0
- package/dist/agent-runners/hook-channel.d.cts.map +1 -0
- package/dist/agent-runners/hook-channel.d.mts +38 -0
- package/dist/agent-runners/hook-channel.d.mts.map +1 -0
- package/dist/agent-runners/hook-channel.mjs +55 -0
- package/dist/agent-runners/hook-channel.mjs.map +1 -0
- package/dist/agent-runners/hooks.cjs +107 -0
- package/dist/agent-runners/hooks.d.cts +41 -0
- package/dist/agent-runners/hooks.d.cts.map +1 -0
- package/dist/agent-runners/hooks.d.mts +41 -0
- package/dist/agent-runners/hooks.d.mts.map +1 -0
- package/dist/agent-runners/hooks.mjs +107 -0
- package/dist/agent-runners/hooks.mjs.map +1 -0
- package/dist/agent-runners/memory-afs.cjs +342 -0
- package/dist/agent-runners/memory-afs.d.cts +221 -0
- package/dist/agent-runners/memory-afs.d.cts.map +1 -0
- package/dist/agent-runners/memory-afs.d.mts +221 -0
- package/dist/agent-runners/memory-afs.d.mts.map +1 -0
- package/dist/agent-runners/memory-afs.mjs +326 -0
- package/dist/agent-runners/memory-afs.mjs.map +1 -0
- package/dist/agent-runners/memory-archive.cjs +263 -0
- package/dist/agent-runners/memory-archive.d.cts +47 -0
- package/dist/agent-runners/memory-archive.d.cts.map +1 -0
- package/dist/agent-runners/memory-archive.d.mts +47 -0
- package/dist/agent-runners/memory-archive.d.mts.map +1 -0
- package/dist/agent-runners/memory-archive.mjs +257 -0
- package/dist/agent-runners/memory-archive.mjs.map +1 -0
- package/dist/agent-runners/orchestrator-runner.cjs +302 -0
- package/dist/agent-runners/orchestrator-runner.d.cts +23 -0
- package/dist/agent-runners/orchestrator-runner.d.cts.map +1 -0
- package/dist/agent-runners/orchestrator-runner.d.mts +23 -0
- package/dist/agent-runners/orchestrator-runner.d.mts.map +1 -0
- package/dist/agent-runners/orchestrator-runner.mjs +303 -0
- package/dist/agent-runners/orchestrator-runner.mjs.map +1 -0
- package/dist/agent-runners/orchestrator-state.cjs +68 -0
- package/dist/agent-runners/orchestrator-state.d.cts +23 -0
- package/dist/agent-runners/orchestrator-state.d.cts.map +1 -0
- package/dist/agent-runners/orchestrator-state.d.mts +23 -0
- package/dist/agent-runners/orchestrator-state.d.mts.map +1 -0
- package/dist/agent-runners/orchestrator-state.mjs +65 -0
- package/dist/agent-runners/orchestrator-state.mjs.map +1 -0
- package/dist/agent-runners/retry.cjs +30 -0
- package/dist/agent-runners/retry.d.cts +13 -0
- package/dist/agent-runners/retry.d.cts.map +1 -0
- package/dist/agent-runners/retry.d.mts +13 -0
- package/dist/agent-runners/retry.d.mts.map +1 -0
- package/dist/agent-runners/retry.mjs +30 -0
- package/dist/agent-runners/retry.mjs.map +1 -0
- package/dist/agent-runners/scratchpad-afs.cjs +276 -0
- package/dist/agent-runners/scratchpad-afs.d.cts +103 -0
- package/dist/agent-runners/scratchpad-afs.d.cts.map +1 -0
- package/dist/agent-runners/scratchpad-afs.d.mts +103 -0
- package/dist/agent-runners/scratchpad-afs.d.mts.map +1 -0
- package/dist/agent-runners/scratchpad-afs.mjs +271 -0
- package/dist/agent-runners/scratchpad-afs.mjs.map +1 -0
- package/dist/agent-runners/stream-router.cjs +72 -0
- package/dist/agent-runners/stream-router.d.cts +22 -0
- package/dist/agent-runners/stream-router.d.cts.map +1 -0
- package/dist/agent-runners/stream-router.d.mts +22 -0
- package/dist/agent-runners/stream-router.d.mts.map +1 -0
- package/dist/agent-runners/stream-router.mjs +72 -0
- package/dist/agent-runners/stream-router.mjs.map +1 -0
- package/dist/agent-runners/system-prompt.cjs +35 -0
- package/dist/agent-runners/system-prompt.d.cts +17 -0
- package/dist/agent-runners/system-prompt.d.cts.map +1 -0
- package/dist/agent-runners/system-prompt.d.mts +17 -0
- package/dist/agent-runners/system-prompt.d.mts.map +1 -0
- package/dist/agent-runners/system-prompt.mjs +34 -0
- package/dist/agent-runners/system-prompt.mjs.map +1 -0
- package/dist/agent-runners/team-modes/aggregates.cjs +36 -0
- package/dist/agent-runners/team-modes/aggregates.mjs +35 -0
- package/dist/agent-runners/team-modes/aggregates.mjs.map +1 -0
- package/dist/agent-runners/team-modes/iterate.cjs +46 -0
- package/dist/agent-runners/team-modes/iterate.mjs +47 -0
- package/dist/agent-runners/team-modes/iterate.mjs.map +1 -0
- package/dist/agent-runners/team-modes/parallel.cjs +59 -0
- package/dist/agent-runners/team-modes/parallel.mjs +60 -0
- package/dist/agent-runners/team-modes/parallel.mjs.map +1 -0
- package/dist/agent-runners/team-modes/reflection.cjs +155 -0
- package/dist/agent-runners/team-modes/reflection.mjs +156 -0
- package/dist/agent-runners/team-modes/reflection.mjs.map +1 -0
- package/dist/agent-runners/team-modes/sequential.cjs +63 -0
- package/dist/agent-runners/team-modes/sequential.mjs +64 -0
- package/dist/agent-runners/team-modes/sequential.mjs.map +1 -0
- package/dist/agent-runners/team-modes/utils.cjs +39 -0
- package/dist/agent-runners/team-modes/utils.mjs +36 -0
- package/dist/agent-runners/team-modes/utils.mjs.map +1 -0
- package/dist/agent-runners/team-runner.cjs +277 -0
- package/dist/agent-runners/team-runner.d.cts +34 -0
- package/dist/agent-runners/team-runner.d.cts.map +1 -0
- package/dist/agent-runners/team-runner.d.mts +34 -0
- package/dist/agent-runners/team-runner.d.mts.map +1 -0
- package/dist/agent-runners/team-runner.mjs +278 -0
- package/dist/agent-runners/team-runner.mjs.map +1 -0
- package/dist/agent-runners/template-context.cjs +32 -0
- package/dist/agent-runners/template-context.d.cts +43 -0
- package/dist/agent-runners/template-context.d.cts.map +1 -0
- package/dist/agent-runners/template-context.d.mts +43 -0
- package/dist/agent-runners/template-context.d.mts.map +1 -0
- package/dist/agent-runners/template-context.mjs +33 -0
- package/dist/agent-runners/template-context.mjs.map +1 -0
- package/dist/index.cjs +123 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.mts +29 -0
- package/dist/index.mjs +29 -0
- package/dist/program/agent-action.cjs +496 -0
- package/dist/program/agent-action.d.cts +42 -0
- package/dist/program/agent-action.d.cts.map +1 -0
- package/dist/program/agent-action.d.mts +42 -0
- package/dist/program/agent-action.d.mts.map +1 -0
- package/dist/program/agent-action.mjs +497 -0
- package/dist/program/agent-action.mjs.map +1 -0
- package/dist/program/agent-messages-tools.cjs +137 -0
- package/dist/program/agent-messages-tools.d.cts +59 -0
- package/dist/program/agent-messages-tools.d.cts.map +1 -0
- package/dist/program/agent-messages-tools.d.mts +59 -0
- package/dist/program/agent-messages-tools.d.mts.map +1 -0
- package/dist/program/agent-messages-tools.mjs +130 -0
- package/dist/program/agent-messages-tools.mjs.map +1 -0
- package/dist/program/agent-runner-registry.cjs +314 -0
- package/dist/program/agent-runner-registry.d.cts +52 -0
- package/dist/program/agent-runner-registry.d.cts.map +1 -0
- package/dist/program/agent-runner-registry.d.mts +52 -0
- package/dist/program/agent-runner-registry.d.mts.map +1 -0
- package/dist/program/agent-runner-registry.mjs +313 -0
- package/dist/program/agent-runner-registry.mjs.map +1 -0
- package/dist/program/agent-subscribe.cjs +72 -0
- package/dist/program/agent-subscribe.d.cts +18 -0
- package/dist/program/agent-subscribe.d.cts.map +1 -0
- package/dist/program/agent-subscribe.d.mts +18 -0
- package/dist/program/agent-subscribe.d.mts.map +1 -0
- package/dist/program/agent-subscribe.mjs +73 -0
- package/dist/program/agent-subscribe.mjs.map +1 -0
- package/dist/program/agent-tools.cjs +135 -0
- package/dist/program/agent-tools.d.cts +35 -0
- package/dist/program/agent-tools.d.cts.map +1 -0
- package/dist/program/agent-tools.d.mts +35 -0
- package/dist/program/agent-tools.d.mts.map +1 -0
- package/dist/program/agent-tools.mjs +136 -0
- package/dist/program/agent-tools.mjs.map +1 -0
- package/dist/program/manifest-nesting.cjs +57 -0
- package/dist/program/manifest-nesting.d.cts +13 -0
- package/dist/program/manifest-nesting.d.cts.map +1 -0
- package/dist/program/manifest-nesting.d.mts +13 -0
- package/dist/program/manifest-nesting.d.mts.map +1 -0
- package/dist/program/manifest-nesting.mjs +57 -0
- package/dist/program/manifest-nesting.mjs.map +1 -0
- package/dist/program/result-contract.cjs +55 -0
- package/dist/program/result-contract.d.cts +23 -0
- package/dist/program/result-contract.d.cts.map +1 -0
- package/dist/program/result-contract.d.mts +23 -0
- package/dist/program/result-contract.d.mts.map +1 -0
- package/dist/program/result-contract.mjs +51 -0
- package/dist/program/result-contract.mjs.map +1 -0
- package/dist/program/runner-error.cjs +71 -0
- package/dist/program/runner-error.d.cts +25 -0
- package/dist/program/runner-error.d.cts.map +1 -0
- package/dist/program/runner-error.d.mts +25 -0
- package/dist/program/runner-error.d.mts.map +1 -0
- package/dist/program/runner-error.mjs +72 -0
- package/dist/program/runner-error.mjs.map +1 -0
- package/dist/program/scoped-afs.cjs +538 -0
- package/dist/program/scoped-afs.d.cts +245 -0
- package/dist/program/scoped-afs.d.cts.map +1 -0
- package/dist/program/scoped-afs.d.mts +245 -0
- package/dist/program/scoped-afs.d.mts.map +1 -0
- package/dist/program/scoped-afs.mjs +531 -0
- package/dist/program/scoped-afs.mjs.map +1 -0
- package/dist/program/session-hierarchy.cjs +1 -0
- package/dist/program/session-hierarchy.d.cts +2 -0
- package/dist/program/session-hierarchy.d.mts +2 -0
- package/dist/program/session-hierarchy.mjs +3 -0
- package/dist/program/tool-discovery/ash-frontmatter.cjs +83 -0
- package/dist/program/tool-discovery/ash-frontmatter.d.cts +21 -0
- package/dist/program/tool-discovery/ash-frontmatter.d.cts.map +1 -0
- package/dist/program/tool-discovery/ash-frontmatter.d.mts +21 -0
- package/dist/program/tool-discovery/ash-frontmatter.d.mts.map +1 -0
- package/dist/program/tool-discovery/ash-frontmatter.mjs +84 -0
- package/dist/program/tool-discovery/ash-frontmatter.mjs.map +1 -0
- package/dist/program/tool-discovery/dot-path-resolver.cjs +60 -0
- package/dist/program/tool-discovery/dot-path-resolver.mjs +61 -0
- package/dist/program/tool-discovery/dot-path-resolver.mjs.map +1 -0
- package/dist/program/tool-discovery/skill-gate.cjs +36 -0
- package/dist/program/tool-discovery/skill-gate.d.cts +10 -0
- package/dist/program/tool-discovery/skill-gate.d.cts.map +1 -0
- package/dist/program/tool-discovery/skill-gate.d.mts +10 -0
- package/dist/program/tool-discovery/skill-gate.d.mts.map +1 -0
- package/dist/program/tool-discovery/skill-gate.mjs +35 -0
- package/dist/program/tool-discovery/skill-gate.mjs.map +1 -0
- package/dist/providers/basic/ash/dist/index.cjs +1809 -0
- package/dist/providers/basic/ash/dist/index.mjs +1807 -0
- package/dist/providers/basic/ash/dist/index.mjs.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { AFSRoot } from "@aigne/afs";
|
|
2
|
+
|
|
3
|
+
//#region src/agent-runners/scratchpad-afs.d.ts
|
|
4
|
+
type ScratchRetention = "run" | "session" | "forever";
|
|
5
|
+
interface AFSScratchLayout {
|
|
6
|
+
/** Base dir for this run — `/modules/memory/runs/<session>/subruns/<runId>` */
|
|
7
|
+
basePath: string;
|
|
8
|
+
stateYml: string;
|
|
9
|
+
messagesJsonl: string;
|
|
10
|
+
eventsJsonl: string;
|
|
11
|
+
historyJsonl: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated Phase 2 migrates scratch to the scope-local `/scratch/` mount.
|
|
15
|
+
* Kept only for the legacy read-path (old sessions) and removed in Phase 6.
|
|
16
|
+
*/
|
|
17
|
+
declare const MEMORY_SCRATCH_ROOT = "/modules/memory";
|
|
18
|
+
/** Root path of the scope-local scratch mount created by `projectForChild`. */
|
|
19
|
+
declare const SCRATCH_SCOPE_ROOT = "/scratch";
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Use `createScratchProvider` + the scope-local `/scratch/` mount.
|
|
22
|
+
* Retained for the legacy read-path and removed in Phase 6.
|
|
23
|
+
*/
|
|
24
|
+
declare function computeScratchLayout(session: string, runId: string): AFSScratchLayout;
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use the scope-local `/scratch/` mount (`createScratchProvider`).
|
|
27
|
+
* Kept for backwards compatibility with pre-Phase-2 callers; removed in P6.
|
|
28
|
+
*/
|
|
29
|
+
declare function provisionScratchViaAFS(afs: AFSRoot, session: string, runId: string): Promise<AFSScratchLayout>;
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated Scope teardown will manage scratch lifetime once P5 lands.
|
|
32
|
+
* Phase 2 keeps this helper for callers still operating on legacy sessions.
|
|
33
|
+
*/
|
|
34
|
+
declare function teardownScratchViaAFS(afs: AFSRoot, session: string, retention?: ScratchRetention): Promise<void>;
|
|
35
|
+
interface ScratchProviderOptions {
|
|
36
|
+
readonly session: string;
|
|
37
|
+
readonly runId?: string;
|
|
38
|
+
readonly retention?: ScratchRetention;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* In-memory scratch provider. Each scope gets its own instance; files stay
|
|
42
|
+
* in memory for the life of the AFS instance (process). Retention shapes
|
|
43
|
+
* teardown behavior once P5 wires it up — P2 stores the flag but the
|
|
44
|
+
* provider itself is a Map.
|
|
45
|
+
*
|
|
46
|
+
* The provider intentionally does not reach back into any real filesystem
|
|
47
|
+
* or KV — keeping scratch per-scope and in-memory is what lets concurrent
|
|
48
|
+
* sub-runs not stomp each other, and what makes scope teardown a
|
|
49
|
+
* single-reference drop.
|
|
50
|
+
*/
|
|
51
|
+
interface ScratchProvider {
|
|
52
|
+
readonly session: string;
|
|
53
|
+
readonly runId?: string;
|
|
54
|
+
readonly retention: ScratchRetention;
|
|
55
|
+
read(path: string): Promise<{
|
|
56
|
+
data: {
|
|
57
|
+
content: string;
|
|
58
|
+
path: string;
|
|
59
|
+
};
|
|
60
|
+
path: string;
|
|
61
|
+
} | null>;
|
|
62
|
+
write(path: string, payload: {
|
|
63
|
+
content: string;
|
|
64
|
+
}): Promise<void>;
|
|
65
|
+
list(path: string): Promise<{
|
|
66
|
+
data: Array<{
|
|
67
|
+
name: string;
|
|
68
|
+
path: string;
|
|
69
|
+
type: "file" | "dir";
|
|
70
|
+
size: number;
|
|
71
|
+
}>;
|
|
72
|
+
list: Array<{
|
|
73
|
+
name: string;
|
|
74
|
+
path: string;
|
|
75
|
+
type: "file" | "dir";
|
|
76
|
+
size: number;
|
|
77
|
+
}>;
|
|
78
|
+
}>;
|
|
79
|
+
stat(path: string): Promise<{
|
|
80
|
+
data: {
|
|
81
|
+
path: string;
|
|
82
|
+
size: number;
|
|
83
|
+
type: "file" | "dir";
|
|
84
|
+
};
|
|
85
|
+
} | null>;
|
|
86
|
+
delete(path: string, options?: {
|
|
87
|
+
recursive?: boolean;
|
|
88
|
+
}): Promise<void>;
|
|
89
|
+
clear(): void;
|
|
90
|
+
}
|
|
91
|
+
declare function createScratchProvider(opts: ScratchProviderOptions): ScratchProvider;
|
|
92
|
+
/**
|
|
93
|
+
* Overlay `/scratch/*` reads/writes/lists/stats/deletes onto the given AFS
|
|
94
|
+
* by routing them to the scratch provider. All other paths fall through to
|
|
95
|
+
* the underlying AFS via the prototype chain (Object.create).
|
|
96
|
+
*
|
|
97
|
+
* The overlay is stateless besides its reference to the provider — two
|
|
98
|
+
* scopes with different providers never see each other's scratch.
|
|
99
|
+
*/
|
|
100
|
+
declare function attachScratchMount<T extends AFSRoot>(afs: T, provider: ScratchProvider): T;
|
|
101
|
+
//#endregion
|
|
102
|
+
export { AFSScratchLayout, MEMORY_SCRATCH_ROOT, SCRATCH_SCOPE_ROOT, ScratchProvider, ScratchProviderOptions, ScratchRetention, attachScratchMount, computeScratchLayout, createScratchProvider, provisionScratchViaAFS, teardownScratchViaAFS };
|
|
103
|
+
//# sourceMappingURL=scratchpad-afs.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratchpad-afs.d.cts","names":[],"sources":["../../src/agent-runners/scratchpad-afs.ts"],"mappings":";;;KAqBY,gBAAA;AAAA,UAEK,gBAAA;EAae;EAX9B,QAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,YAAA;AAAA;;;AAkDF;;cA3Ca,mBAAA;;cAGA,kBAAA;;;;;iBAwCG,oBAAA,CAAqB,OAAA,UAAiB,KAAA,WAAgB,gBAAA;;;;;iBAiBhD,sBAAA,CACpB,GAAA,EAAK,OAAA,EACL,OAAA,UACA,KAAA,WACC,OAAA,CAAQ,gBAAA;;;;;iBAgBW,qBAAA,CACpB,GAAA,EAAK,OAAA,EACL,OAAA,UACA,SAAA,GAAW,gBAAA,GACV,OAAA;AAAA,UAkBc,sBAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,GAAY,gBAAA;AAAA;AAzBvB;;;;;;;;;;;AAAA,UAuCiB,eAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;EACpB,IAAA,CAAK,IAAA,WAAe,OAAA;IAAU,IAAA;MAAQ,OAAA;MAAiB,IAAA;IAAA;IAAgB,IAAA;EAAA;EACvE,KAAA,CAAM,IAAA,UAAc,OAAA;IAAW,OAAA;EAAA,IAAoB,OAAA;EACnD,IAAA,CAAK,IAAA,WAAe,OAAA;IAClB,IAAA,EAAM,KAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;MAAsB,IAAA;IAAA;IAChE,IAAA,EAAM,KAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;MAAsB,IAAA;IAAA;EAAA;EAElE,IAAA,CACE,IAAA,WACC,OAAA;IAAU,IAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;IAAA;EAAA;EACjD,MAAA,CAAO,IAAA,UAAc,OAAA;IAAY,SAAA;EAAA,IAAwB,OAAA;EACzD,KAAA;AAAA;AAAA,iBAiBc,qBAAA,CAAsB,IAAA,EAAM,sBAAA,GAAyB,eAAA;;;;;;;;;iBAgHrD,kBAAA,WAA6B,OAAA,CAAA,CAAS,GAAA,EAAK,CAAA,EAAG,QAAA,EAAU,eAAA,GAAkB,CAAA"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { AFSRoot } from "@aigne/afs";
|
|
2
|
+
|
|
3
|
+
//#region src/agent-runners/scratchpad-afs.d.ts
|
|
4
|
+
type ScratchRetention = "run" | "session" | "forever";
|
|
5
|
+
interface AFSScratchLayout {
|
|
6
|
+
/** Base dir for this run — `/modules/memory/runs/<session>/subruns/<runId>` */
|
|
7
|
+
basePath: string;
|
|
8
|
+
stateYml: string;
|
|
9
|
+
messagesJsonl: string;
|
|
10
|
+
eventsJsonl: string;
|
|
11
|
+
historyJsonl: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated Phase 2 migrates scratch to the scope-local `/scratch/` mount.
|
|
15
|
+
* Kept only for the legacy read-path (old sessions) and removed in Phase 6.
|
|
16
|
+
*/
|
|
17
|
+
declare const MEMORY_SCRATCH_ROOT = "/modules/memory";
|
|
18
|
+
/** Root path of the scope-local scratch mount created by `projectForChild`. */
|
|
19
|
+
declare const SCRATCH_SCOPE_ROOT = "/scratch";
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Use `createScratchProvider` + the scope-local `/scratch/` mount.
|
|
22
|
+
* Retained for the legacy read-path and removed in Phase 6.
|
|
23
|
+
*/
|
|
24
|
+
declare function computeScratchLayout(session: string, runId: string): AFSScratchLayout;
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use the scope-local `/scratch/` mount (`createScratchProvider`).
|
|
27
|
+
* Kept for backwards compatibility with pre-Phase-2 callers; removed in P6.
|
|
28
|
+
*/
|
|
29
|
+
declare function provisionScratchViaAFS(afs: AFSRoot, session: string, runId: string): Promise<AFSScratchLayout>;
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated Scope teardown will manage scratch lifetime once P5 lands.
|
|
32
|
+
* Phase 2 keeps this helper for callers still operating on legacy sessions.
|
|
33
|
+
*/
|
|
34
|
+
declare function teardownScratchViaAFS(afs: AFSRoot, session: string, retention?: ScratchRetention): Promise<void>;
|
|
35
|
+
interface ScratchProviderOptions {
|
|
36
|
+
readonly session: string;
|
|
37
|
+
readonly runId?: string;
|
|
38
|
+
readonly retention?: ScratchRetention;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* In-memory scratch provider. Each scope gets its own instance; files stay
|
|
42
|
+
* in memory for the life of the AFS instance (process). Retention shapes
|
|
43
|
+
* teardown behavior once P5 wires it up — P2 stores the flag but the
|
|
44
|
+
* provider itself is a Map.
|
|
45
|
+
*
|
|
46
|
+
* The provider intentionally does not reach back into any real filesystem
|
|
47
|
+
* or KV — keeping scratch per-scope and in-memory is what lets concurrent
|
|
48
|
+
* sub-runs not stomp each other, and what makes scope teardown a
|
|
49
|
+
* single-reference drop.
|
|
50
|
+
*/
|
|
51
|
+
interface ScratchProvider {
|
|
52
|
+
readonly session: string;
|
|
53
|
+
readonly runId?: string;
|
|
54
|
+
readonly retention: ScratchRetention;
|
|
55
|
+
read(path: string): Promise<{
|
|
56
|
+
data: {
|
|
57
|
+
content: string;
|
|
58
|
+
path: string;
|
|
59
|
+
};
|
|
60
|
+
path: string;
|
|
61
|
+
} | null>;
|
|
62
|
+
write(path: string, payload: {
|
|
63
|
+
content: string;
|
|
64
|
+
}): Promise<void>;
|
|
65
|
+
list(path: string): Promise<{
|
|
66
|
+
data: Array<{
|
|
67
|
+
name: string;
|
|
68
|
+
path: string;
|
|
69
|
+
type: "file" | "dir";
|
|
70
|
+
size: number;
|
|
71
|
+
}>;
|
|
72
|
+
list: Array<{
|
|
73
|
+
name: string;
|
|
74
|
+
path: string;
|
|
75
|
+
type: "file" | "dir";
|
|
76
|
+
size: number;
|
|
77
|
+
}>;
|
|
78
|
+
}>;
|
|
79
|
+
stat(path: string): Promise<{
|
|
80
|
+
data: {
|
|
81
|
+
path: string;
|
|
82
|
+
size: number;
|
|
83
|
+
type: "file" | "dir";
|
|
84
|
+
};
|
|
85
|
+
} | null>;
|
|
86
|
+
delete(path: string, options?: {
|
|
87
|
+
recursive?: boolean;
|
|
88
|
+
}): Promise<void>;
|
|
89
|
+
clear(): void;
|
|
90
|
+
}
|
|
91
|
+
declare function createScratchProvider(opts: ScratchProviderOptions): ScratchProvider;
|
|
92
|
+
/**
|
|
93
|
+
* Overlay `/scratch/*` reads/writes/lists/stats/deletes onto the given AFS
|
|
94
|
+
* by routing them to the scratch provider. All other paths fall through to
|
|
95
|
+
* the underlying AFS via the prototype chain (Object.create).
|
|
96
|
+
*
|
|
97
|
+
* The overlay is stateless besides its reference to the provider — two
|
|
98
|
+
* scopes with different providers never see each other's scratch.
|
|
99
|
+
*/
|
|
100
|
+
declare function attachScratchMount<T extends AFSRoot>(afs: T, provider: ScratchProvider): T;
|
|
101
|
+
//#endregion
|
|
102
|
+
export { AFSScratchLayout, MEMORY_SCRATCH_ROOT, SCRATCH_SCOPE_ROOT, ScratchProvider, ScratchProviderOptions, ScratchRetention, attachScratchMount, computeScratchLayout, createScratchProvider, provisionScratchViaAFS, teardownScratchViaAFS };
|
|
103
|
+
//# sourceMappingURL=scratchpad-afs.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratchpad-afs.d.mts","names":[],"sources":["../../src/agent-runners/scratchpad-afs.ts"],"mappings":";;;KAqBY,gBAAA;AAAA,UAEK,gBAAA;EAae;EAX9B,QAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,YAAA;AAAA;;;AAkDF;;cA3Ca,mBAAA;;cAGA,kBAAA;;;;;iBAwCG,oBAAA,CAAqB,OAAA,UAAiB,KAAA,WAAgB,gBAAA;;;;;iBAiBhD,sBAAA,CACpB,GAAA,EAAK,OAAA,EACL,OAAA,UACA,KAAA,WACC,OAAA,CAAQ,gBAAA;;;;;iBAgBW,qBAAA,CACpB,GAAA,EAAK,OAAA,EACL,OAAA,UACA,SAAA,GAAW,gBAAA,GACV,OAAA;AAAA,UAkBc,sBAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,GAAY,gBAAA;AAAA;AAzBvB;;;;;;;;;;;AAAA,UAuCiB,eAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;EACpB,IAAA,CAAK,IAAA,WAAe,OAAA;IAAU,IAAA;MAAQ,OAAA;MAAiB,IAAA;IAAA;IAAgB,IAAA;EAAA;EACvE,KAAA,CAAM,IAAA,UAAc,OAAA;IAAW,OAAA;EAAA,IAAoB,OAAA;EACnD,IAAA,CAAK,IAAA,WAAe,OAAA;IAClB,IAAA,EAAM,KAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;MAAsB,IAAA;IAAA;IAChE,IAAA,EAAM,KAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;MAAsB,IAAA;IAAA;EAAA;EAElE,IAAA,CACE,IAAA,WACC,OAAA;IAAU,IAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;IAAA;EAAA;EACjD,MAAA,CAAO,IAAA,UAAc,OAAA;IAAY,SAAA;EAAA,IAAwB,OAAA;EACzD,KAAA;AAAA;AAAA,iBAiBc,qBAAA,CAAsB,IAAA,EAAM,sBAAA,GAAyB,eAAA;;;;;;;;;iBAgHrD,kBAAA,WAA6B,OAAA,CAAA,CAAS,GAAA,EAAK,CAAA,EAAG,QAAA,EAAU,eAAA,GAAkB,CAAA"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { joinURL } from "ufo";
|
|
2
|
+
|
|
3
|
+
//#region src/agent-runners/scratchpad-afs.ts
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Phase 2 migrates scratch to the scope-local `/scratch/` mount.
|
|
6
|
+
* Kept only for the legacy read-path (old sessions) and removed in Phase 6.
|
|
7
|
+
*/
|
|
8
|
+
const MEMORY_SCRATCH_ROOT = "/modules/memory";
|
|
9
|
+
/** Root path of the scope-local scratch mount created by `projectForChild`. */
|
|
10
|
+
const SCRATCH_SCOPE_ROOT = "/scratch";
|
|
11
|
+
function validatePathComponent(value, label) {
|
|
12
|
+
if (typeof value !== "string" || value.length === 0) throw new TypeError(`SCRATCH_INVALID_INPUT: ${label} must be a non-empty string`);
|
|
13
|
+
if (value.includes("..")) throw new Error(`SCRATCH_INVALID_INPUT: path traversal disallowed in ${label}`);
|
|
14
|
+
if (value.includes("\0")) throw new Error(`SCRATCH_INVALID_INPUT: null byte disallowed in ${label}`);
|
|
15
|
+
if (value.includes("/") || value.includes("\\")) throw new Error(`SCRATCH_INVALID_INPUT: path separator disallowed in ${label}`);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reject scratch-local paths that try to escape the `/scratch/` root or
|
|
20
|
+
* smuggle control characters. Runs on every read/write/list/stat/delete
|
|
21
|
+
* against the scope-local mount.
|
|
22
|
+
*/
|
|
23
|
+
function assertScratchPath(path) {
|
|
24
|
+
if (typeof path !== "string" || path.length === 0) throw new Error(`SCRATCH_INVALID_PATH: path must be a non-empty string`);
|
|
25
|
+
if (path.includes("\0")) throw new Error(`SCRATCH_INVALID_PATH: null byte disallowed`);
|
|
26
|
+
if (path.split("/").some((s) => s === "..")) throw new Error(`SCRATCH_INVALID_PATH: path traversal disallowed (".." segment)`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated Use `createScratchProvider` + the scope-local `/scratch/` mount.
|
|
30
|
+
* Retained for the legacy read-path and removed in Phase 6.
|
|
31
|
+
*/
|
|
32
|
+
function computeScratchLayout(session, runId) {
|
|
33
|
+
const basePath = joinURL(MEMORY_SCRATCH_ROOT, "runs", validatePathComponent(session, "session"), "subruns", validatePathComponent(runId, "runId"));
|
|
34
|
+
return {
|
|
35
|
+
basePath,
|
|
36
|
+
stateYml: joinURL(basePath, "state.yml"),
|
|
37
|
+
messagesJsonl: joinURL(basePath, "messages.jsonl"),
|
|
38
|
+
eventsJsonl: joinURL(basePath, "events.jsonl"),
|
|
39
|
+
historyJsonl: joinURL(basePath, "history.jsonl")
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @deprecated Use the scope-local `/scratch/` mount (`createScratchProvider`).
|
|
44
|
+
* Kept for backwards compatibility with pre-Phase-2 callers; removed in P6.
|
|
45
|
+
*/
|
|
46
|
+
async function provisionScratchViaAFS(afs, session, runId) {
|
|
47
|
+
if (!afs.write) throw new Error("SCRATCH_NO_WRITE: host AFS does not expose a write method");
|
|
48
|
+
const layout = computeScratchLayout(session, runId);
|
|
49
|
+
await afs.write(layout.stateYml, { content: "" });
|
|
50
|
+
await afs.write(layout.messagesJsonl, { content: "" });
|
|
51
|
+
await afs.write(layout.eventsJsonl, { content: "" });
|
|
52
|
+
await afs.write(layout.historyJsonl, { content: "" });
|
|
53
|
+
return layout;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated Scope teardown will manage scratch lifetime once P5 lands.
|
|
57
|
+
* Phase 2 keeps this helper for callers still operating on legacy sessions.
|
|
58
|
+
*/
|
|
59
|
+
async function teardownScratchViaAFS(afs, session, retention = "session") {
|
|
60
|
+
if (retention === "forever" || retention === "run") return;
|
|
61
|
+
const s = validatePathComponent(session, "session");
|
|
62
|
+
const anyAfs = afs;
|
|
63
|
+
if (typeof anyAfs.delete !== "function") return;
|
|
64
|
+
const sessionPath = joinURL(MEMORY_SCRATCH_ROOT, "runs", s);
|
|
65
|
+
try {
|
|
66
|
+
await anyAfs.delete(sessionPath, { recursive: true });
|
|
67
|
+
} catch {}
|
|
68
|
+
}
|
|
69
|
+
function normalizeScratchPath(path) {
|
|
70
|
+
assertScratchPath(path);
|
|
71
|
+
if (path === SCRATCH_SCOPE_ROOT) return SCRATCH_SCOPE_ROOT;
|
|
72
|
+
if (path.startsWith(`${SCRATCH_SCOPE_ROOT}/`)) {
|
|
73
|
+
const trimmed = path.replace(/\/+$/, "");
|
|
74
|
+
return trimmed.length < 8 ? SCRATCH_SCOPE_ROOT : trimmed;
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`SCRATCH_PATH_OUT_OF_SCOPE: ${path} is not inside ${SCRATCH_SCOPE_ROOT}/`);
|
|
77
|
+
}
|
|
78
|
+
function isScratchPath(path) {
|
|
79
|
+
return path === SCRATCH_SCOPE_ROOT || path.startsWith(`${SCRATCH_SCOPE_ROOT}/`);
|
|
80
|
+
}
|
|
81
|
+
function createScratchProvider(opts) {
|
|
82
|
+
validatePathComponent(opts.session, "session");
|
|
83
|
+
if (opts.runId !== void 0) validatePathComponent(opts.runId, "runId");
|
|
84
|
+
const retention = opts.retention ?? "session";
|
|
85
|
+
const store = /* @__PURE__ */ new Map();
|
|
86
|
+
return {
|
|
87
|
+
session: opts.session,
|
|
88
|
+
runId: opts.runId,
|
|
89
|
+
retention,
|
|
90
|
+
async read(path) {
|
|
91
|
+
const norm = normalizeScratchPath(path);
|
|
92
|
+
if (!store.has(norm)) return null;
|
|
93
|
+
return {
|
|
94
|
+
data: {
|
|
95
|
+
content: store.get(norm),
|
|
96
|
+
path: norm
|
|
97
|
+
},
|
|
98
|
+
path: norm
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
async write(path, payload) {
|
|
102
|
+
const norm = normalizeScratchPath(path);
|
|
103
|
+
if (norm === SCRATCH_SCOPE_ROOT) throw new Error(`SCRATCH_INVALID_PATH: cannot write to scratch root`);
|
|
104
|
+
const content = typeof payload?.content === "string" ? payload.content : "";
|
|
105
|
+
store.set(norm, content);
|
|
106
|
+
},
|
|
107
|
+
async list(path) {
|
|
108
|
+
const norm = normalizeScratchPath(path);
|
|
109
|
+
const prefix = norm === SCRATCH_SCOPE_ROOT ? `${SCRATCH_SCOPE_ROOT}/` : `${norm}/`;
|
|
110
|
+
const files = [];
|
|
111
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
112
|
+
for (const stored of store.keys()) {
|
|
113
|
+
if (!stored.startsWith(prefix)) continue;
|
|
114
|
+
const rest = stored.slice(prefix.length);
|
|
115
|
+
const slash = rest.indexOf("/");
|
|
116
|
+
if (slash === -1) {
|
|
117
|
+
const content = store.get(stored) ?? "";
|
|
118
|
+
files.push({
|
|
119
|
+
name: rest,
|
|
120
|
+
path: stored,
|
|
121
|
+
type: "file",
|
|
122
|
+
size: Buffer.byteLength(content, "utf8")
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
const dir = rest.slice(0, slash);
|
|
126
|
+
dirs.add(dir);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const list = [];
|
|
130
|
+
for (const d of dirs) list.push({
|
|
131
|
+
name: d,
|
|
132
|
+
path: `${prefix}${d}`,
|
|
133
|
+
type: "dir",
|
|
134
|
+
size: 0
|
|
135
|
+
});
|
|
136
|
+
list.push(...files);
|
|
137
|
+
return {
|
|
138
|
+
data: list,
|
|
139
|
+
list
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
async stat(path) {
|
|
143
|
+
const norm = normalizeScratchPath(path);
|
|
144
|
+
if (norm === SCRATCH_SCOPE_ROOT) return { data: {
|
|
145
|
+
path: norm,
|
|
146
|
+
size: 0,
|
|
147
|
+
type: "dir"
|
|
148
|
+
} };
|
|
149
|
+
if (store.has(norm)) {
|
|
150
|
+
const content = store.get(norm);
|
|
151
|
+
return { data: {
|
|
152
|
+
path: norm,
|
|
153
|
+
size: Buffer.byteLength(content, "utf8"),
|
|
154
|
+
type: "file"
|
|
155
|
+
} };
|
|
156
|
+
}
|
|
157
|
+
const prefix = `${norm}/`;
|
|
158
|
+
for (const k of store.keys()) if (k.startsWith(prefix)) return { data: {
|
|
159
|
+
path: norm,
|
|
160
|
+
size: 0,
|
|
161
|
+
type: "dir"
|
|
162
|
+
} };
|
|
163
|
+
return null;
|
|
164
|
+
},
|
|
165
|
+
async delete(path, options) {
|
|
166
|
+
const norm = normalizeScratchPath(path);
|
|
167
|
+
if (norm === SCRATCH_SCOPE_ROOT) {
|
|
168
|
+
if (options?.recursive) {
|
|
169
|
+
store.clear();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
throw new Error(`SCRATCH_INVALID_PATH: cannot delete scratch root non-recursively`);
|
|
173
|
+
}
|
|
174
|
+
if (store.has(norm)) {
|
|
175
|
+
store.delete(norm);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (options?.recursive) {
|
|
179
|
+
const prefix = `${norm}/`;
|
|
180
|
+
for (const k of Array.from(store.keys())) if (k.startsWith(prefix)) store.delete(k);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
clear() {
|
|
184
|
+
store.clear();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Overlay `/scratch/*` reads/writes/lists/stats/deletes onto the given AFS
|
|
190
|
+
* by routing them to the scratch provider. All other paths fall through to
|
|
191
|
+
* the underlying AFS via the prototype chain (Object.create).
|
|
192
|
+
*
|
|
193
|
+
* The overlay is stateless besides its reference to the provider — two
|
|
194
|
+
* scopes with different providers never see each other's scratch.
|
|
195
|
+
*/
|
|
196
|
+
function attachScratchMount(afs, provider) {
|
|
197
|
+
const child = Object.create(afs);
|
|
198
|
+
Object.defineProperty(child, "read", {
|
|
199
|
+
value: async (path, options) => {
|
|
200
|
+
if (isScratchPath(path)) {
|
|
201
|
+
const result = await provider.read(path);
|
|
202
|
+
if (result) return result;
|
|
203
|
+
const err = /* @__PURE__ */ new Error(`SCRATCH_NOT_FOUND: ${path}`);
|
|
204
|
+
err.code = "NOT_FOUND";
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
return afs.read.call(afs, path, options);
|
|
208
|
+
},
|
|
209
|
+
enumerable: false,
|
|
210
|
+
writable: false,
|
|
211
|
+
configurable: false
|
|
212
|
+
});
|
|
213
|
+
Object.defineProperty(child, "write", {
|
|
214
|
+
value: async (path, payload, options) => {
|
|
215
|
+
if (isScratchPath(path)) {
|
|
216
|
+
await provider.write(path, payload);
|
|
217
|
+
return {
|
|
218
|
+
success: true,
|
|
219
|
+
data: { path }
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (typeof afs.write !== "function") throw new Error(`SCRATCH_NO_UNDERLYING_WRITE: afs.write not available for ${path}`);
|
|
223
|
+
return afs.write.call(afs, path, payload, options);
|
|
224
|
+
},
|
|
225
|
+
enumerable: false,
|
|
226
|
+
writable: false,
|
|
227
|
+
configurable: false
|
|
228
|
+
});
|
|
229
|
+
Object.defineProperty(child, "list", {
|
|
230
|
+
value: async (path, options) => {
|
|
231
|
+
if (isScratchPath(path)) return provider.list(path);
|
|
232
|
+
return afs.list.call(afs, path, options);
|
|
233
|
+
},
|
|
234
|
+
enumerable: false,
|
|
235
|
+
writable: false,
|
|
236
|
+
configurable: false
|
|
237
|
+
});
|
|
238
|
+
Object.defineProperty(child, "stat", {
|
|
239
|
+
value: async (path, options) => {
|
|
240
|
+
if (isScratchPath(path)) {
|
|
241
|
+
const result = await provider.stat(path);
|
|
242
|
+
if (result) return result;
|
|
243
|
+
const err = /* @__PURE__ */ new Error(`SCRATCH_NOT_FOUND: ${path}`);
|
|
244
|
+
err.code = "NOT_FOUND";
|
|
245
|
+
throw err;
|
|
246
|
+
}
|
|
247
|
+
return afs.stat.call(afs, path, options);
|
|
248
|
+
},
|
|
249
|
+
enumerable: false,
|
|
250
|
+
writable: false,
|
|
251
|
+
configurable: false
|
|
252
|
+
});
|
|
253
|
+
Object.defineProperty(child, "delete", {
|
|
254
|
+
value: async (path, options) => {
|
|
255
|
+
if (isScratchPath(path)) {
|
|
256
|
+
await provider.delete(path, options);
|
|
257
|
+
return { success: true };
|
|
258
|
+
}
|
|
259
|
+
if (typeof afs.delete !== "function") return { success: false };
|
|
260
|
+
return afs.delete.call(afs, path, options);
|
|
261
|
+
},
|
|
262
|
+
enumerable: false,
|
|
263
|
+
writable: false,
|
|
264
|
+
configurable: false
|
|
265
|
+
});
|
|
266
|
+
return child;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
export { MEMORY_SCRATCH_ROOT, SCRATCH_SCOPE_ROOT, attachScratchMount, computeScratchLayout, createScratchProvider, provisionScratchViaAFS, teardownScratchViaAFS };
|
|
271
|
+
//# sourceMappingURL=scratchpad-afs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratchpad-afs.mjs","names":[],"sources":["../../src/agent-runners/scratchpad-afs.ts"],"sourcesContent":["/**\n * Scratchpad — per-scope ephemeral filesystem for agent runs.\n *\n * Phase 2 (agent-runtime-afs-first): scratch is now a **per-scope mount**\n * at `/scratch/*`. `createScratchProvider` builds an in-memory store that\n * `projectForChild` overlays onto each child scope via\n * `attachScratchMount`. Runners then read/write `/scratch/state.yml`,\n * `/scratch/hook-channel.jsonl`, etc. without caring which backend holds\n * them.\n *\n * The legacy path `/modules/memory/runs/<session>/subruns/<runId>/`\n * — exposed as `MEMORY_SCRATCH_ROOT` + `provisionScratchViaAFS` +\n * `teardownScratchViaAFS` — is retained as a *read-only* legacy helper\n * so old sessions remain inspectable. New sessions must go through the\n * `/scratch/*` mount. All legacy helpers carry `@deprecated` markers and\n * disappear with Phase 6's RunnerContext sweep.\n */\n\nimport type { AFSRoot } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\n\nexport type ScratchRetention = \"run\" | \"session\" | \"forever\";\n\nexport interface AFSScratchLayout {\n /** Base dir for this run — `/modules/memory/runs/<session>/subruns/<runId>` */\n basePath: string;\n stateYml: string;\n messagesJsonl: string;\n eventsJsonl: string;\n historyJsonl: string;\n}\n\n/**\n * @deprecated Phase 2 migrates scratch to the scope-local `/scratch/` mount.\n * Kept only for the legacy read-path (old sessions) and removed in Phase 6.\n */\nexport const MEMORY_SCRATCH_ROOT = \"/modules/memory\";\n\n/** Root path of the scope-local scratch mount created by `projectForChild`. */\nexport const SCRATCH_SCOPE_ROOT = \"/scratch\";\n\nfunction validatePathComponent(value: unknown, label: string): string {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new TypeError(`SCRATCH_INVALID_INPUT: ${label} must be a non-empty string`);\n }\n if (value.includes(\"..\")) {\n throw new Error(`SCRATCH_INVALID_INPUT: path traversal disallowed in ${label}`);\n }\n if (value.includes(\"\\0\")) {\n throw new Error(`SCRATCH_INVALID_INPUT: null byte disallowed in ${label}`);\n }\n if (value.includes(\"/\") || value.includes(\"\\\\\")) {\n throw new Error(`SCRATCH_INVALID_INPUT: path separator disallowed in ${label}`);\n }\n return value;\n}\n\n/**\n * Reject scratch-local paths that try to escape the `/scratch/` root or\n * smuggle control characters. Runs on every read/write/list/stat/delete\n * against the scope-local mount.\n */\nfunction assertScratchPath(path: string): void {\n if (typeof path !== \"string\" || path.length === 0) {\n throw new Error(`SCRATCH_INVALID_PATH: path must be a non-empty string`);\n }\n if (path.includes(\"\\0\")) {\n throw new Error(`SCRATCH_INVALID_PATH: null byte disallowed`);\n }\n const segments = path.split(\"/\");\n if (segments.some((s) => s === \"..\")) {\n throw new Error(`SCRATCH_INVALID_PATH: path traversal disallowed (\"..\" segment)`);\n }\n}\n\n/**\n * @deprecated Use `createScratchProvider` + the scope-local `/scratch/` mount.\n * Retained for the legacy read-path and removed in Phase 6.\n */\nexport function computeScratchLayout(session: string, runId: string): AFSScratchLayout {\n const s = validatePathComponent(session, \"session\");\n const r = validatePathComponent(runId, \"runId\");\n const basePath = joinURL(MEMORY_SCRATCH_ROOT, \"runs\", s, \"subruns\", r);\n return {\n basePath,\n stateYml: joinURL(basePath, \"state.yml\"),\n messagesJsonl: joinURL(basePath, \"messages.jsonl\"),\n eventsJsonl: joinURL(basePath, \"events.jsonl\"),\n historyJsonl: joinURL(basePath, \"history.jsonl\"),\n };\n}\n\n/**\n * @deprecated Use the scope-local `/scratch/` mount (`createScratchProvider`).\n * Kept for backwards compatibility with pre-Phase-2 callers; removed in P6.\n */\nexport async function provisionScratchViaAFS(\n afs: AFSRoot,\n session: string,\n runId: string,\n): Promise<AFSScratchLayout> {\n if (!afs.write) {\n throw new Error(\"SCRATCH_NO_WRITE: host AFS does not expose a write method\");\n }\n const layout = computeScratchLayout(session, runId);\n await afs.write(layout.stateYml, { content: \"\" });\n await afs.write(layout.messagesJsonl, { content: \"\" });\n await afs.write(layout.eventsJsonl, { content: \"\" });\n await afs.write(layout.historyJsonl, { content: \"\" });\n return layout;\n}\n\n/**\n * @deprecated Scope teardown will manage scratch lifetime once P5 lands.\n * Phase 2 keeps this helper for callers still operating on legacy sessions.\n */\nexport async function teardownScratchViaAFS(\n afs: AFSRoot,\n session: string,\n retention: ScratchRetention = \"session\",\n): Promise<void> {\n if (retention === \"forever\" || retention === \"run\") return;\n const s = validatePathComponent(session, \"session\");\n const anyAfs = afs as any;\n if (typeof anyAfs.delete !== \"function\") return;\n\n const sessionPath = joinURL(MEMORY_SCRATCH_ROOT, \"runs\", s);\n try {\n await anyAfs.delete(sessionPath, { recursive: true });\n } catch {\n // best-effort — session may not exist, or backing provider may reject\n }\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2 — scope-local `/scratch/` provider + overlay.\n// ---------------------------------------------------------------------------\n\nexport interface ScratchProviderOptions {\n readonly session: string;\n readonly runId?: string;\n readonly retention?: ScratchRetention;\n}\n\n/**\n * In-memory scratch provider. Each scope gets its own instance; files stay\n * in memory for the life of the AFS instance (process). Retention shapes\n * teardown behavior once P5 wires it up — P2 stores the flag but the\n * provider itself is a Map.\n *\n * The provider intentionally does not reach back into any real filesystem\n * or KV — keeping scratch per-scope and in-memory is what lets concurrent\n * sub-runs not stomp each other, and what makes scope teardown a\n * single-reference drop.\n */\nexport interface ScratchProvider {\n readonly session: string;\n readonly runId?: string;\n readonly retention: ScratchRetention;\n read(path: string): Promise<{ data: { content: string; path: string }; path: string } | null>;\n write(path: string, payload: { content: string }): Promise<void>;\n list(path: string): Promise<{\n data: Array<{ name: string; path: string; type: \"file\" | \"dir\"; size: number }>;\n list: Array<{ name: string; path: string; type: \"file\" | \"dir\"; size: number }>;\n }>;\n stat(\n path: string,\n ): Promise<{ data: { path: string; size: number; type: \"file\" | \"dir\" } } | null>;\n delete(path: string, options?: { recursive?: boolean }): Promise<void>;\n clear(): void;\n}\n\nfunction normalizeScratchPath(path: string): string {\n assertScratchPath(path);\n if (path === SCRATCH_SCOPE_ROOT) return SCRATCH_SCOPE_ROOT;\n if (path.startsWith(`${SCRATCH_SCOPE_ROOT}/`)) {\n const trimmed = path.replace(/\\/+$/, \"\");\n return trimmed.length < SCRATCH_SCOPE_ROOT.length ? SCRATCH_SCOPE_ROOT : trimmed;\n }\n throw new Error(`SCRATCH_PATH_OUT_OF_SCOPE: ${path} is not inside ${SCRATCH_SCOPE_ROOT}/`);\n}\n\nfunction isScratchPath(path: string): boolean {\n return path === SCRATCH_SCOPE_ROOT || path.startsWith(`${SCRATCH_SCOPE_ROOT}/`);\n}\n\nexport function createScratchProvider(opts: ScratchProviderOptions): ScratchProvider {\n validatePathComponent(opts.session, \"session\");\n if (opts.runId !== undefined) validatePathComponent(opts.runId, \"runId\");\n const retention: ScratchRetention = opts.retention ?? \"session\";\n const store = new Map<string, string>();\n\n return {\n session: opts.session,\n runId: opts.runId,\n retention,\n\n async read(path) {\n const norm = normalizeScratchPath(path);\n if (!store.has(norm)) return null;\n const content = store.get(norm)!;\n return { data: { content, path: norm }, path: norm };\n },\n\n async write(path, payload) {\n const norm = normalizeScratchPath(path);\n if (norm === SCRATCH_SCOPE_ROOT) {\n throw new Error(`SCRATCH_INVALID_PATH: cannot write to scratch root`);\n }\n const content = typeof payload?.content === \"string\" ? payload.content : \"\";\n store.set(norm, content);\n },\n\n async list(path) {\n const norm = normalizeScratchPath(path);\n const prefix = norm === SCRATCH_SCOPE_ROOT ? `${SCRATCH_SCOPE_ROOT}/` : `${norm}/`;\n const files: Array<{ name: string; path: string; type: \"file\" | \"dir\"; size: number }> = [];\n const dirs = new Set<string>();\n for (const stored of store.keys()) {\n if (!stored.startsWith(prefix)) continue;\n const rest = stored.slice(prefix.length);\n const slash = rest.indexOf(\"/\");\n if (slash === -1) {\n const content = store.get(stored) ?? \"\";\n files.push({\n name: rest,\n path: stored,\n type: \"file\",\n size: Buffer.byteLength(content, \"utf8\"),\n });\n } else {\n const dir = rest.slice(0, slash);\n dirs.add(dir);\n }\n }\n const list: Array<{ name: string; path: string; type: \"file\" | \"dir\"; size: number }> = [];\n for (const d of dirs) {\n list.push({ name: d, path: `${prefix}${d}`, type: \"dir\", size: 0 });\n }\n list.push(...files);\n return { data: list, list };\n },\n\n async stat(path) {\n const norm = normalizeScratchPath(path);\n if (norm === SCRATCH_SCOPE_ROOT) {\n return { data: { path: norm, size: 0, type: \"dir\" } };\n }\n if (store.has(norm)) {\n const content = store.get(norm)!;\n return {\n data: { path: norm, size: Buffer.byteLength(content, \"utf8\"), type: \"file\" },\n };\n }\n const prefix = `${norm}/`;\n for (const k of store.keys()) {\n if (k.startsWith(prefix)) {\n return { data: { path: norm, size: 0, type: \"dir\" } };\n }\n }\n return null;\n },\n\n async delete(path, options) {\n const norm = normalizeScratchPath(path);\n if (norm === SCRATCH_SCOPE_ROOT) {\n if (options?.recursive) {\n store.clear();\n return;\n }\n throw new Error(`SCRATCH_INVALID_PATH: cannot delete scratch root non-recursively`);\n }\n if (store.has(norm)) {\n store.delete(norm);\n return;\n }\n if (options?.recursive) {\n const prefix = `${norm}/`;\n for (const k of Array.from(store.keys())) {\n if (k.startsWith(prefix)) store.delete(k);\n }\n }\n },\n\n clear() {\n store.clear();\n },\n };\n}\n\n/**\n * Overlay `/scratch/*` reads/writes/lists/stats/deletes onto the given AFS\n * by routing them to the scratch provider. All other paths fall through to\n * the underlying AFS via the prototype chain (Object.create).\n *\n * The overlay is stateless besides its reference to the provider — two\n * scopes with different providers never see each other's scratch.\n */\nexport function attachScratchMount<T extends AFSRoot>(afs: T, provider: ScratchProvider): T {\n const child = Object.create(afs) as T;\n\n Object.defineProperty(child, \"read\", {\n value: async (path: string, options?: unknown) => {\n if (isScratchPath(path)) {\n const result = await provider.read(path);\n if (result) return result;\n const err = new Error(`SCRATCH_NOT_FOUND: ${path}`);\n (err as any).code = \"NOT_FOUND\";\n throw err;\n }\n return (afs.read as any)!.call(afs, path, options);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(child, \"write\", {\n value: async (path: string, payload: { content: string }, options?: unknown) => {\n if (isScratchPath(path)) {\n await provider.write(path, payload);\n return { success: true, data: { path } } as any;\n }\n if (typeof afs.write !== \"function\") {\n throw new Error(`SCRATCH_NO_UNDERLYING_WRITE: afs.write not available for ${path}`);\n }\n return (afs.write as any)!.call(afs, path, payload, options);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(child, \"list\", {\n value: async (path: string, options?: unknown) => {\n if (isScratchPath(path)) {\n return provider.list(path);\n }\n return (afs.list as any)!.call(afs, path, options);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(child, \"stat\", {\n value: async (path: string, options?: unknown) => {\n if (isScratchPath(path)) {\n const result = await provider.stat(path);\n if (result) return result;\n const err = new Error(`SCRATCH_NOT_FOUND: ${path}`);\n (err as any).code = \"NOT_FOUND\";\n throw err;\n }\n return (afs.stat as any)!.call(afs, path, options);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(child, \"delete\", {\n value: async (path: string, options?: { recursive?: boolean }) => {\n if (isScratchPath(path)) {\n await provider.delete(path, options);\n return { success: true } as any;\n }\n if (typeof (afs as any).delete !== \"function\") return { success: false } as any;\n return (afs as any).delete!.call(afs, path, options);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n return child;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
let ufo = require("ufo");
|
|
2
|
+
|
|
3
|
+
//#region src/agent-runners/stream-router.ts
|
|
4
|
+
const UI_SESSION_RE = /^\/(?:dev\/)?ui\/[^/]+\/sessions\/([^/]+)/;
|
|
5
|
+
function detectUISessionPath(session) {
|
|
6
|
+
if (!session) return null;
|
|
7
|
+
const trimmed = session.replace(/\/+$/, "");
|
|
8
|
+
const match = UI_SESSION_RE.exec(trimmed);
|
|
9
|
+
if (!match) return null;
|
|
10
|
+
const [full] = match;
|
|
11
|
+
return full;
|
|
12
|
+
}
|
|
13
|
+
function createStreamProgressRouter(opts) {
|
|
14
|
+
const sessionPath = opts.sessionPath ?? null;
|
|
15
|
+
if (!sessionPath || !opts.nodeId) return null;
|
|
16
|
+
const patchPath = (0, ufo.joinURL)(sessionPath, ".actions", "aup_patch");
|
|
17
|
+
const throttleMs = opts.throttleMs ?? 150;
|
|
18
|
+
const state = {
|
|
19
|
+
streamingText: "",
|
|
20
|
+
thinkingText: "",
|
|
21
|
+
dirty: false
|
|
22
|
+
};
|
|
23
|
+
let timer = null;
|
|
24
|
+
let lastFlush = Promise.resolve();
|
|
25
|
+
const sendPatch = async () => {
|
|
26
|
+
if (!state.dirty) return;
|
|
27
|
+
state.dirty = false;
|
|
28
|
+
const patchState = {};
|
|
29
|
+
if (state.streamingText) patchState.streamingText = state.streamingText;
|
|
30
|
+
if (state.thinkingText) patchState.thinkingText = state.thinkingText;
|
|
31
|
+
const ops = [{
|
|
32
|
+
op: "update",
|
|
33
|
+
id: opts.nodeId,
|
|
34
|
+
state: patchState
|
|
35
|
+
}];
|
|
36
|
+
try {
|
|
37
|
+
await opts.afs.exec(patchPath, { ops }, {});
|
|
38
|
+
} catch {}
|
|
39
|
+
};
|
|
40
|
+
const scheduleFlush = () => {
|
|
41
|
+
if (timer) return;
|
|
42
|
+
timer = setTimeout(() => {
|
|
43
|
+
timer = null;
|
|
44
|
+
lastFlush = sendPatch();
|
|
45
|
+
}, throttleMs);
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
onProgress: (event) => {
|
|
49
|
+
if (event.type === "llm_delta" && typeof event.text === "string") {
|
|
50
|
+
state.streamingText += event.text;
|
|
51
|
+
state.dirty = true;
|
|
52
|
+
scheduleFlush();
|
|
53
|
+
} else if (event.type === "thinking_delta" && typeof event.text === "string") {
|
|
54
|
+
state.thinkingText += event.text;
|
|
55
|
+
state.dirty = true;
|
|
56
|
+
scheduleFlush();
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
flush: async () => {
|
|
60
|
+
if (timer) {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
timer = null;
|
|
63
|
+
}
|
|
64
|
+
await lastFlush;
|
|
65
|
+
await sendPatch();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
exports.createStreamProgressRouter = createStreamProgressRouter;
|
|
72
|
+
exports.detectUISessionPath = detectUISessionPath;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AFSRoot } from "@aigne/afs";
|
|
2
|
+
|
|
3
|
+
//#region src/agent-runners/stream-router.d.ts
|
|
4
|
+
declare function detectUISessionPath(session: string | undefined | null): string | null;
|
|
5
|
+
interface StreamProgressRouterOptions {
|
|
6
|
+
afs: AFSRoot;
|
|
7
|
+
sessionPath: string | null | undefined;
|
|
8
|
+
nodeId?: string;
|
|
9
|
+
throttleMs?: number;
|
|
10
|
+
}
|
|
11
|
+
interface StreamProgressRouter {
|
|
12
|
+
onProgress: (event: {
|
|
13
|
+
type: string;
|
|
14
|
+
round?: number;
|
|
15
|
+
text?: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
flush: () => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
declare function createStreamProgressRouter(opts: StreamProgressRouterOptions): StreamProgressRouter | null;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { StreamProgressRouter, StreamProgressRouterOptions, createStreamProgressRouter, detectUISessionPath };
|
|
22
|
+
//# sourceMappingURL=stream-router.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-router.d.cts","names":[],"sources":["../../src/agent-runners/stream-router.ts"],"mappings":";;;iBAuBgB,mBAAA,CAAoB,OAAA;AAAA,UAUnB,2BAAA;EACf,GAAA,EAAK,OAAA;EACL,WAAA;EACA,MAAA;EACA,UAAA;AAAA;AAAA,UAGe,oBAAA;EACf,UAAA,GAAa,KAAA;IAAS,IAAA;IAAc,KAAA;IAAgB,IAAA;EAAA;EACpD,KAAA,QAAa,OAAA;AAAA;AAAA,iBASC,0BAAA,CACd,IAAA,EAAM,2BAAA,GACL,oBAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AFSRoot } from "@aigne/afs";
|
|
2
|
+
|
|
3
|
+
//#region src/agent-runners/stream-router.d.ts
|
|
4
|
+
declare function detectUISessionPath(session: string | undefined | null): string | null;
|
|
5
|
+
interface StreamProgressRouterOptions {
|
|
6
|
+
afs: AFSRoot;
|
|
7
|
+
sessionPath: string | null | undefined;
|
|
8
|
+
nodeId?: string;
|
|
9
|
+
throttleMs?: number;
|
|
10
|
+
}
|
|
11
|
+
interface StreamProgressRouter {
|
|
12
|
+
onProgress: (event: {
|
|
13
|
+
type: string;
|
|
14
|
+
round?: number;
|
|
15
|
+
text?: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
flush: () => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
declare function createStreamProgressRouter(opts: StreamProgressRouterOptions): StreamProgressRouter | null;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { StreamProgressRouter, StreamProgressRouterOptions, createStreamProgressRouter, detectUISessionPath };
|
|
22
|
+
//# sourceMappingURL=stream-router.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-router.d.mts","names":[],"sources":["../../src/agent-runners/stream-router.ts"],"mappings":";;;iBAuBgB,mBAAA,CAAoB,OAAA;AAAA,UAUnB,2BAAA;EACf,GAAA,EAAK,OAAA;EACL,WAAA;EACA,MAAA;EACA,UAAA;AAAA;AAAA,UAGe,oBAAA;EACf,UAAA,GAAa,KAAA;IAAS,IAAA;IAAc,KAAA;IAAgB,IAAA;EAAA;EACpD,KAAA,QAAa,OAAA;AAAA;AAAA,iBASC,0BAAA,CACd,IAAA,EAAM,2BAAA,GACL,oBAAA"}
|