@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,538 @@
|
|
|
1
|
+
const require_index = require('../providers/basic/ash/dist/index.cjs');
|
|
2
|
+
const require_budget = require('../agent-runners/budget.cjs');
|
|
3
|
+
const require_scratchpad_afs = require('../agent-runners/scratchpad-afs.cjs');
|
|
4
|
+
const require_memory_afs = require('../agent-runners/memory-afs.cjs');
|
|
5
|
+
const require_agent_messages_tools = require('./agent-messages-tools.cjs');
|
|
6
|
+
let _aigne_afs = require("@aigne/afs");
|
|
7
|
+
|
|
8
|
+
//#region src/program/scoped-afs.ts
|
|
9
|
+
/**
|
|
10
|
+
* Chain-depth hard cap. Mirrors `HARD_CAP` in
|
|
11
|
+
* `providers/basic/ash/src/spawn-depth.ts`; kept in sync manually because
|
|
12
|
+
* importing across package boundaries for a constant isn't worth the
|
|
13
|
+
* dependency. Any change there must be reflected here.
|
|
14
|
+
*
|
|
15
|
+
* Semantics match `spawn-depth.ts`: a child whose post-increment depth
|
|
16
|
+
* would be **>= HARD_CAP** is rejected with `CHAIN_DEPTH_EXCEEDED`. With
|
|
17
|
+
* root.chainDepth = 0 this means the deepest reachable child is depth 9;
|
|
18
|
+
* attempting to spawn depth 10 throws.
|
|
19
|
+
*/
|
|
20
|
+
const CHAIN_DEPTH_HARD_CAP = 10;
|
|
21
|
+
/** Default ops applied when a manifest tool entry omits `ops`. */
|
|
22
|
+
const DEFAULT_TOOL_OPS = [
|
|
23
|
+
"read",
|
|
24
|
+
"list",
|
|
25
|
+
"exec",
|
|
26
|
+
"query"
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Built-in messaging tool path — every scope surfaces
|
|
30
|
+
* `/proc/messaging/tools/*`
|
|
31
|
+
* so the LLM can call `agent_post_message` / `agent_read_messages` without
|
|
32
|
+
* each manifest having to declare them. See B32 in
|
|
33
|
+
* `providers/basic/ash/src/agent-run.ts`.
|
|
34
|
+
*/
|
|
35
|
+
const MESSAGING_TOOL_PATH = require_agent_messages_tools.MESSAGING_TOOLS_GLOB;
|
|
36
|
+
/**
|
|
37
|
+
* Budget mount — per-scope `/.meta/budget/{limit,remaining,consumed}` state
|
|
38
|
+
* files driven by the exec middleware in `attachBudgetMount`. Path contract:
|
|
39
|
+
*
|
|
40
|
+
* - `read("/.meta/budget/limit")` → configured ceiling (tokens)
|
|
41
|
+
* - `read("/.meta/budget/remaining")` → `max(0, limit - consumed)`
|
|
42
|
+
* - `read("/.meta/budget/consumed")` → tokens decremented so far
|
|
43
|
+
* - `write("/.meta/budget/*", ...)` → always `PERMISSION_DENIED`; only
|
|
44
|
+
* the middleware may mutate state (via the internal `BudgetState` ref).
|
|
45
|
+
* - `list("/.meta/budget")` → three-entry listing (above keys).
|
|
46
|
+
*
|
|
47
|
+
* The exec middleware wraps the underlying `afs.exec`:
|
|
48
|
+
* 1. Pre-check `consumed < limit`; otherwise throw `BUDGET_EXHAUSTED`.
|
|
49
|
+
* 2. Call underlying exec.
|
|
50
|
+
* 3. Extract `tokens_used` from the result and serialize the increment
|
|
51
|
+
* against the rootSession mutex so concurrent sub-runs don't race.
|
|
52
|
+
*
|
|
53
|
+
* Child scopes created by `projectForChild` inherit via a new `BudgetState`
|
|
54
|
+
* whose `parent` points back to the caller's state. Each scope's middleware
|
|
55
|
+
* only decrements its *own* `consumed` — propagation to ancestors happens
|
|
56
|
+
* naturally because `child.exec` delegates to `parent.exec` through the
|
|
57
|
+
* prototype chain, so every ancestor's middleware runs once per call and
|
|
58
|
+
* the rootSession mutex keeps the sequence of increments linear.
|
|
59
|
+
*/
|
|
60
|
+
const BUDGET_MOUNT_ROOT = "/.meta/budget";
|
|
61
|
+
const BUDGET_KEY_LIMIT = "limit";
|
|
62
|
+
const BUDGET_KEY_REMAINING = "remaining";
|
|
63
|
+
const BUDGET_KEY_CONSUMED = "consumed";
|
|
64
|
+
const BUDGET_KEYS = [
|
|
65
|
+
BUDGET_KEY_LIMIT,
|
|
66
|
+
BUDGET_KEY_REMAINING,
|
|
67
|
+
BUDGET_KEY_CONSUMED
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* Process-local mutex map keyed on `rootSession`. Every decrement for a
|
|
71
|
+
* given scope tree serializes against the same promise chain, so two
|
|
72
|
+
* concurrent sub-runs sharing a rootSession cannot double-count or see a
|
|
73
|
+
* mid-update view of `consumed`. Phase 2 will swap the Map for an AFS KV
|
|
74
|
+
* provider so the guarantee holds across processes; the API shape stays.
|
|
75
|
+
*/
|
|
76
|
+
const rootBudgetLocks = /* @__PURE__ */ new Map();
|
|
77
|
+
async function withRootBudgetLock(rootSession, fn) {
|
|
78
|
+
const stored = (rootBudgetLocks.get(rootSession) ?? Promise.resolve()).then(fn, fn);
|
|
79
|
+
rootBudgetLocks.set(rootSession, stored);
|
|
80
|
+
try {
|
|
81
|
+
return await stored;
|
|
82
|
+
} finally {
|
|
83
|
+
if (rootBudgetLocks.get(rootSession) === stored) rootBudgetLocks.delete(rootSession);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function createBudgetState(init) {
|
|
87
|
+
if (!init.rootSession || typeof init.rootSession !== "string") throw new Error(`BUDGET_INVALID: rootSession must be a non-empty string`);
|
|
88
|
+
if (typeof init.limit !== "number" || Number.isNaN(init.limit) || init.limit < 0) throw new Error(`BUDGET_INVALID: limit must be a non-negative number`);
|
|
89
|
+
return {
|
|
90
|
+
rootSession: init.rootSession,
|
|
91
|
+
limit: Math.floor(init.limit),
|
|
92
|
+
consumed: 0
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function budgetRemaining(state) {
|
|
96
|
+
return Math.max(0, state.limit - state.consumed);
|
|
97
|
+
}
|
|
98
|
+
function isBudgetPath(path) {
|
|
99
|
+
return path === BUDGET_MOUNT_ROOT || path.startsWith(`${BUDGET_MOUNT_ROOT}/`);
|
|
100
|
+
}
|
|
101
|
+
function parseBudgetKey(path) {
|
|
102
|
+
if (!path.startsWith(`${BUDGET_MOUNT_ROOT}/`)) return null;
|
|
103
|
+
const key = path.slice(14);
|
|
104
|
+
return BUDGET_KEYS.includes(key) ? key : null;
|
|
105
|
+
}
|
|
106
|
+
function budgetValue(state, key) {
|
|
107
|
+
if (key === BUDGET_KEY_LIMIT) return state.limit;
|
|
108
|
+
if (key === BUDGET_KEY_CONSUMED) return state.consumed;
|
|
109
|
+
return budgetRemaining(state);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Extract `tokens_used` from an exec result. Supports both legacy
|
|
113
|
+
* `data.total_tokens` (the agent-run envelope) and `data._meta.tokens_used`
|
|
114
|
+
* (team/orchestrator aggregate meta). Anything else → 0.
|
|
115
|
+
*/
|
|
116
|
+
function extractTokensUsed(result) {
|
|
117
|
+
const data = result?.data;
|
|
118
|
+
if (!data || typeof data !== "object") return 0;
|
|
119
|
+
const candidates = [data.total_tokens, data._meta?.tokens_used];
|
|
120
|
+
for (const value of candidates) if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Overlay the budget mount on an AFS root:
|
|
125
|
+
* - `/.meta/budget/{limit,remaining,consumed}` → live reads
|
|
126
|
+
* - `/.meta/budget/*` writes → `PERMISSION_DENIED`
|
|
127
|
+
* - `exec(...)` → pre-check `BUDGET_EXHAUSTED`, then decrement by
|
|
128
|
+
* `tokens_used` under the rootSession mutex.
|
|
129
|
+
*
|
|
130
|
+
* The overlay is non-enumerable (matches the scratch/memory pattern) and
|
|
131
|
+
* transparent for non-budget paths, which fall through via the prototype
|
|
132
|
+
* chain. Every projected child attaches its own overlay backed by its own
|
|
133
|
+
* `BudgetState`, so sibling scopes never see each other's `consumed`.
|
|
134
|
+
*/
|
|
135
|
+
function attachBudgetMount(afs, state) {
|
|
136
|
+
const child = Object.create(afs);
|
|
137
|
+
Object.defineProperty(child, "read", {
|
|
138
|
+
value: async (path, options) => {
|
|
139
|
+
const key = parseBudgetKey(path);
|
|
140
|
+
if (key) return {
|
|
141
|
+
success: true,
|
|
142
|
+
data: {
|
|
143
|
+
content: String(budgetValue(state, key)),
|
|
144
|
+
path
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
return afs.read.call(afs, path, options);
|
|
148
|
+
},
|
|
149
|
+
enumerable: false,
|
|
150
|
+
writable: false,
|
|
151
|
+
configurable: false
|
|
152
|
+
});
|
|
153
|
+
Object.defineProperty(child, "write", {
|
|
154
|
+
value: async (path, payload, options) => {
|
|
155
|
+
if (isBudgetPath(path)) {
|
|
156
|
+
const err = /* @__PURE__ */ new Error(`PERMISSION_DENIED: ${path} is managed by the budget exec middleware and cannot be written directly`);
|
|
157
|
+
err.code = "PERMISSION_DENIED";
|
|
158
|
+
throw err;
|
|
159
|
+
}
|
|
160
|
+
if (typeof afs.write !== "function") throw new Error(`BUDGET_NO_UNDERLYING_WRITE: afs.write not available for ${path}`);
|
|
161
|
+
return afs.write.call(afs, path, payload, options);
|
|
162
|
+
},
|
|
163
|
+
enumerable: false,
|
|
164
|
+
writable: false,
|
|
165
|
+
configurable: false
|
|
166
|
+
});
|
|
167
|
+
Object.defineProperty(child, "list", {
|
|
168
|
+
value: async (path, options) => {
|
|
169
|
+
if (path === BUDGET_MOUNT_ROOT || path === `${BUDGET_MOUNT_ROOT}/`) return {
|
|
170
|
+
success: true,
|
|
171
|
+
data: { list: BUDGET_KEYS.map((name) => ({
|
|
172
|
+
path: `${BUDGET_MOUNT_ROOT}/${name}`,
|
|
173
|
+
name,
|
|
174
|
+
type: "file"
|
|
175
|
+
})) }
|
|
176
|
+
};
|
|
177
|
+
return afs.list.call(afs, path, options);
|
|
178
|
+
},
|
|
179
|
+
enumerable: false,
|
|
180
|
+
writable: false,
|
|
181
|
+
configurable: false
|
|
182
|
+
});
|
|
183
|
+
Object.defineProperty(child, "exec", {
|
|
184
|
+
value: async (path, args, options) => {
|
|
185
|
+
if (state.consumed >= state.limit) {
|
|
186
|
+
const err = /* @__PURE__ */ new Error(`BUDGET_EXHAUSTED: scope budget exhausted (path=${path}, limit=${state.limit}, consumed=${state.consumed})`);
|
|
187
|
+
err.code = "BUDGET_EXHAUSTED";
|
|
188
|
+
throw err;
|
|
189
|
+
}
|
|
190
|
+
const result = await afs.exec.call(afs, path, args, options);
|
|
191
|
+
const used = extractTokensUsed(result);
|
|
192
|
+
if (used > 0) await withRootBudgetLock(state.rootSession, () => {
|
|
193
|
+
state.consumed += used;
|
|
194
|
+
});
|
|
195
|
+
return result;
|
|
196
|
+
},
|
|
197
|
+
enumerable: false,
|
|
198
|
+
writable: false,
|
|
199
|
+
configurable: false
|
|
200
|
+
});
|
|
201
|
+
return child;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Resolve a child scope's budget. The child's effective limit is the
|
|
205
|
+
* result of `resolveBudget({manifest, parentRemaining})`; consumed starts
|
|
206
|
+
* at 0. Ancestor updates are handled by the middleware chain itself
|
|
207
|
+
* (each scope's middleware runs once per call via the prototype chain),
|
|
208
|
+
* so the child's `BudgetState` is independent from the parent's.
|
|
209
|
+
*
|
|
210
|
+
* Returns `undefined` when the parent has no active budget — zero-overhead
|
|
211
|
+
* path for legacy callers that never opt in.
|
|
212
|
+
*
|
|
213
|
+
* Inheritance rules (P5 deferred nit documented here for clarity):
|
|
214
|
+
*
|
|
215
|
+
* - Parent has budget, child manifest declares one → `resolveBudget`
|
|
216
|
+
* clamps `min(childBudget.totalTokens, parentRemaining)`.
|
|
217
|
+
* - Parent has budget, child manifest omits budget → `resolveBudget` uses
|
|
218
|
+
* `DEFAULT_TOTAL_TOKENS` (80k) then clamps to `parentRemaining`. Net
|
|
219
|
+
* effect: an undeclared child never exceeds the parent's remaining
|
|
220
|
+
* window, which is the conservative default.
|
|
221
|
+
* - Parent has no budget → child is unbudgeted too; the whole
|
|
222
|
+
* `/.meta/budget/*` overlay is skipped (zero-overhead legacy path).
|
|
223
|
+
*
|
|
224
|
+
* The clamp is only a ceiling. Actual spend is still accounted per call
|
|
225
|
+
* via the exec middleware (`afs.exec` → decrement under `rootSession`
|
|
226
|
+
* mutex), so siblings can't double-spend the parent's remaining window.
|
|
227
|
+
*/
|
|
228
|
+
function deriveChildBudgetState(parent, childBudget) {
|
|
229
|
+
if (!parent) return void 0;
|
|
230
|
+
const resolved = require_budget.resolveBudget({
|
|
231
|
+
manifest: childBudget,
|
|
232
|
+
parentRemaining: budgetRemaining(parent)
|
|
233
|
+
});
|
|
234
|
+
return createBudgetState({
|
|
235
|
+
rootSession: parent.rootSession,
|
|
236
|
+
limit: resolved.totalTokens
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function assertSession(session) {
|
|
240
|
+
if (session === void 0) return;
|
|
241
|
+
if (typeof session !== "string" || session.length === 0) throw new Error(`SCOPE_INVALID_INPUT: session must be a non-empty string`);
|
|
242
|
+
if (session.includes("/") || session.includes("\\")) throw new Error(`SCOPE_INVALID_INPUT: session must not contain path separators`);
|
|
243
|
+
if (session.includes("\0")) throw new Error(`SCOPE_INVALID_INPUT: session must not contain null bytes`);
|
|
244
|
+
}
|
|
245
|
+
function assertMemberPath(memberPath) {
|
|
246
|
+
if (typeof memberPath !== "string" || memberPath.length === 0) throw new Error(`SCOPE_INVALID_MEMBER: memberPath must be a non-empty string`);
|
|
247
|
+
if (memberPath.includes("\0")) throw new Error(`SCOPE_INVALID_MEMBER: memberPath must not contain null bytes`);
|
|
248
|
+
if (memberPath.split("/").some((s) => s === "..")) throw new Error(`SCOPE_INVALID_MEMBER: memberPath must not traverse parent directories`);
|
|
249
|
+
}
|
|
250
|
+
function assertChildManifest(manifest) {
|
|
251
|
+
if (!manifest || typeof manifest !== "object") throw new Error(`SCOPE_INVALID_INPUT: childManifest is required`);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Normalize a manifest's `tools` field into `ToolEntry[]`, rejecting shapes
|
|
255
|
+
* that would let a dispatcher smuggle traversal or typo past intersection:
|
|
256
|
+
* - non-string / empty path → TOOL_PATH_INVALID
|
|
257
|
+
* - path containing `..` or `\0` → TOOL_PATH_INVALID
|
|
258
|
+
* - ops must be a non-empty string[] when provided
|
|
259
|
+
*
|
|
260
|
+
* The Phase 1 contract: one call site (projectForChild) owns normalization;
|
|
261
|
+
* older runner-local normalize helpers delegate here.
|
|
262
|
+
*/
|
|
263
|
+
function normalizeManifestTools(manifest) {
|
|
264
|
+
const raw = manifest.tools ?? [];
|
|
265
|
+
const result = [];
|
|
266
|
+
raw.forEach((t, idx) => {
|
|
267
|
+
const path = typeof t === "string" ? t : t?.path;
|
|
268
|
+
if (typeof path !== "string" || path.length === 0) throw new Error(`TOOL_PATH_INVALID: manifest.tools[${idx}].path must be a non-empty string`);
|
|
269
|
+
if (path.includes("\0")) throw new Error(`TOOL_PATH_INVALID: manifest.tools[${idx}].path must not contain null bytes`);
|
|
270
|
+
if (path.includes("..")) throw new Error(`TOOL_PATH_INVALID: manifest.tools[${idx}].path must not contain ".."`);
|
|
271
|
+
if (typeof t === "string") {
|
|
272
|
+
result.push({
|
|
273
|
+
path,
|
|
274
|
+
ops: [...DEFAULT_TOOL_OPS]
|
|
275
|
+
});
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const ops = t.ops ?? [...DEFAULT_TOOL_OPS];
|
|
279
|
+
if (!Array.isArray(ops) || ops.length === 0 || ops.some((op) => typeof op !== "string")) throw new Error(`TOOL_PATH_INVALID: manifest.tools[${idx}].ops must be a non-empty string[]`);
|
|
280
|
+
const entry = {
|
|
281
|
+
path,
|
|
282
|
+
ops: require_index.withQueryPairing(ops)
|
|
283
|
+
};
|
|
284
|
+
if (t.maxDepth != null) entry.maxDepth = t.maxDepth;
|
|
285
|
+
result.push(entry);
|
|
286
|
+
});
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Phase 5 canonical session accessor — runners must read the effective
|
|
291
|
+
* session id from `ctx.afs.scope.session` rather than from the legacy
|
|
292
|
+
* `context.session` field. This helper keeps back-compat while the four
|
|
293
|
+
* runners are swapped: if the AFS already carries a scope, return
|
|
294
|
+
* `scope.session`; otherwise fall back to the deprecated `fallback`
|
|
295
|
+
* argument. P6 removes the fallback path once `RunnerContext.session` is
|
|
296
|
+
* deleted.
|
|
297
|
+
*/
|
|
298
|
+
function runnerSession(afs, fallback) {
|
|
299
|
+
return afs.scope?.session ?? fallback;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Phase 5 canonical parent-session accessor. Mirrors `runnerSession` but
|
|
303
|
+
* surfaces the parent's session id so runners can tag sub-runs without
|
|
304
|
+
* consulting the legacy `context.parentSession` field. Returns undefined
|
|
305
|
+
* for root scopes (no parent) — callers must treat undefined as "root".
|
|
306
|
+
*/
|
|
307
|
+
function runnerParentSession(afs, fallback) {
|
|
308
|
+
return afs.scope?.parentSession ?? fallback;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Shared session-resolution ladder for every runner. Reads session and
|
|
312
|
+
* parentSession from scope first (legacy context fields only as fallback
|
|
313
|
+
* until P6) and, when both are set, derives the child session id.
|
|
314
|
+
*
|
|
315
|
+
* Collapses the ai / ash / team / orchestrator entry blocks into one
|
|
316
|
+
* place — any adjustment to the derivation rule now has a single owner.
|
|
317
|
+
*/
|
|
318
|
+
function resolveChildSession(afs, ctx, deriveChildSession) {
|
|
319
|
+
const parentSession = runnerParentSession(afs, ctx.parentSession);
|
|
320
|
+
let session = runnerSession(afs, ctx.session);
|
|
321
|
+
if (parentSession && session) session = deriveChildSession(parentSession);
|
|
322
|
+
return {
|
|
323
|
+
session,
|
|
324
|
+
parentSession
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Lift a raw `AFSRoot` into a root-level `AgentScope`. Root scopes are
|
|
329
|
+
* unbounded by construction — `scope.allowedTools` is the caller's own
|
|
330
|
+
* manifest tools (or fully permissive when omitted), and `chainDepth` is 0.
|
|
331
|
+
*
|
|
332
|
+
* Top-level runners (agent-run action handler, test harnesses) use this to
|
|
333
|
+
* bootstrap the scope chain; downstream runners never construct a root
|
|
334
|
+
* scope themselves. Omit `manifestTools` (or pass `[]`) to keep the root
|
|
335
|
+
* fully permissive — useful for tests that don't declare tools.
|
|
336
|
+
*/
|
|
337
|
+
function rootAgentScope(afs, opts) {
|
|
338
|
+
assertSession(opts.session);
|
|
339
|
+
const allowedTools = opts.manifestTools && opts.manifestTools.length > 0 ? opts.manifestTools : [{
|
|
340
|
+
path: "/**",
|
|
341
|
+
ops: [
|
|
342
|
+
"read",
|
|
343
|
+
"list",
|
|
344
|
+
"exec",
|
|
345
|
+
"write",
|
|
346
|
+
"search",
|
|
347
|
+
"query"
|
|
348
|
+
]
|
|
349
|
+
}];
|
|
350
|
+
let withBudget = afs;
|
|
351
|
+
let budgetState;
|
|
352
|
+
if (opts.budget) {
|
|
353
|
+
const resolved = require_budget.resolveBudget({ manifest: opts.budget });
|
|
354
|
+
budgetState = createBudgetState({
|
|
355
|
+
rootSession: opts.session,
|
|
356
|
+
limit: resolved.totalTokens
|
|
357
|
+
});
|
|
358
|
+
withBudget = attachBudgetMount(afs, budgetState);
|
|
359
|
+
}
|
|
360
|
+
return attachScope(withBudget, {
|
|
361
|
+
session: opts.session,
|
|
362
|
+
rootSession: opts.session,
|
|
363
|
+
chainDepth: 0,
|
|
364
|
+
allowedPaths: allowedTools.map((t) => t.path),
|
|
365
|
+
allowedTools,
|
|
366
|
+
budget: budgetState,
|
|
367
|
+
memoryDomain: opts.memoryDomain
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Top-level runner bootstrap — if the caller's AFS is already a scope, use
|
|
372
|
+
* it verbatim; otherwise synthesize a root scope and attach a fresh
|
|
373
|
+
* `/scratch/*` mount. Team and orchestrator runners call this so hook
|
|
374
|
+
* events and `state.yml` writes land in the scope-local scratch rather
|
|
375
|
+
* than the legacy `/modules/memory/runs/` tree.
|
|
376
|
+
*
|
|
377
|
+
* Pass `manifestTools` + `session` to drive the synthetic root scope's
|
|
378
|
+
* descriptor; the caller's own manifest is typically the source, and
|
|
379
|
+
* `scratchRetention` follows `manifest.scratch` (run → session default).
|
|
380
|
+
*/
|
|
381
|
+
function ensureScopeWithMounts(afs, opts) {
|
|
382
|
+
if (afs.scope) return afs;
|
|
383
|
+
return require_scratchpad_afs.attachScratchMount(rootAgentScope(afs, {
|
|
384
|
+
session: opts.session,
|
|
385
|
+
manifestTools: opts.manifestTools,
|
|
386
|
+
budget: opts.budget,
|
|
387
|
+
memoryDomain: require_memory_afs.extractManifestDomain(opts.memory)
|
|
388
|
+
}), opts.scratchProvider ?? require_scratchpad_afs.createScratchProvider({
|
|
389
|
+
session: sanitizeSessionForScratch(opts.session),
|
|
390
|
+
retention: opts.scratchRetention ?? "session"
|
|
391
|
+
}));
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Resolve the `AgentScope` a parent runner projects children from.
|
|
395
|
+
*
|
|
396
|
+
* Phase 6 — if the caller already handed us a scoped AFS (via
|
|
397
|
+
* `projectForChild` / `ensureScopeWithMounts`), reuse it: its `allowedTools`
|
|
398
|
+
* is already the post-intersection view. Otherwise synthesize a root scope
|
|
399
|
+
* from the caller's `manifest.tools`, normalized via `normalizeManifestTools`
|
|
400
|
+
* for a single source of truth. Callers that want a tighter inherited
|
|
401
|
+
* set must hand over a scoped AFS built via `projectForChild` or
|
|
402
|
+
* `ensureScopeWithMounts`.
|
|
403
|
+
*/
|
|
404
|
+
function resolveParentAgentScope(opts) {
|
|
405
|
+
if (opts.afs.scope) return opts.afs;
|
|
406
|
+
const manifestTools = normalizeManifestTools(opts.manifest);
|
|
407
|
+
return rootAgentScope(opts.afs, {
|
|
408
|
+
session: opts.session ?? "root",
|
|
409
|
+
manifestTools: manifestTools.length > 0 ? manifestTools : void 0
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
function attachScope(afs, scope) {
|
|
413
|
+
const child = Object.create(afs);
|
|
414
|
+
Object.defineProperty(child, "scope", {
|
|
415
|
+
value: scope,
|
|
416
|
+
enumerable: true,
|
|
417
|
+
writable: false,
|
|
418
|
+
configurable: false
|
|
419
|
+
});
|
|
420
|
+
return child;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Narrow down `parent` for a child agent:
|
|
424
|
+
* - path projection via existing `projectSubAgent` (rewrite + readonly)
|
|
425
|
+
* - tool ACL intersection via existing `intersectTools` (paths + ops)
|
|
426
|
+
* - scope descriptor: session / rootSession / chainDepth+1 / allowedPaths
|
|
427
|
+
*
|
|
428
|
+
* If the parent has a non-empty `scope.allowedTools` and the child declares
|
|
429
|
+
* a non-empty `manifest.tools` that doesn't overlap (intersection empty),
|
|
430
|
+
* we throw `TOOL_INTERSECTION_EMPTY` — an empty intersection means the
|
|
431
|
+
* dispatcher has asked for an unreachable child scope, which is a hard
|
|
432
|
+
* error rather than a silently-permissive default.
|
|
433
|
+
*
|
|
434
|
+
* See design.md §5 for the full six-step mount composition; P2–P5 add
|
|
435
|
+
* scratch / memory / budget / session arms to the same function.
|
|
436
|
+
*/
|
|
437
|
+
function projectForChild(parent, options) {
|
|
438
|
+
assertChildManifest(options.childManifest);
|
|
439
|
+
assertMemberPath(options.memberPath);
|
|
440
|
+
assertSession(options.session);
|
|
441
|
+
if (!parent || typeof parent !== "object" || !parent.scope) throw new Error(`SCOPE_INVALID_INPUT: parent scope is required`);
|
|
442
|
+
const nextDepth = parent.scope.chainDepth + 1;
|
|
443
|
+
if (nextDepth >= CHAIN_DEPTH_HARD_CAP) throw new Error(`CHAIN_DEPTH_EXCEEDED: chainDepth ${nextDepth} reaches hard cap ${CHAIN_DEPTH_HARD_CAP}`);
|
|
444
|
+
const childDeclaredTools = normalizeManifestTools(options.childManifest);
|
|
445
|
+
const parentAllowed = parent.scope.allowedTools;
|
|
446
|
+
const intersected = childDeclaredTools.length === 0 ? [] : require_index.intersectTools([...parentAllowed], childDeclaredTools);
|
|
447
|
+
if (childDeclaredTools.length > 0 && intersected.length === 0) throw new Error(`TOOL_INTERSECTION_EMPTY: child manifest declares tools that don't intersect parent scope`);
|
|
448
|
+
const withMessaging = ensureMessagingTool(intersected);
|
|
449
|
+
const projectedAfs = (0, _aigne_afs.projectSubAgent)(parent, {
|
|
450
|
+
memberPath: options.memberPath,
|
|
451
|
+
mode: "readonly"
|
|
452
|
+
});
|
|
453
|
+
const childSession = options.session ?? deriveDefaultChildSession(parent.scope.session, options.memberPath);
|
|
454
|
+
const withScratch = require_scratchpad_afs.attachScratchMount(projectedAfs, require_scratchpad_afs.createScratchProvider({
|
|
455
|
+
session: sanitizeSessionForScratch(childSession),
|
|
456
|
+
retention: options.childManifest.scratch ? "session" : "run"
|
|
457
|
+
}));
|
|
458
|
+
const memoryDomain = isMemoryEnabled(options.childManifest.memory) ? require_memory_afs.resolveMemoryDomain({
|
|
459
|
+
manifestMemory: options.childManifest.memory,
|
|
460
|
+
parentDomain: parent.scope.memoryDomain,
|
|
461
|
+
memberPath: options.memberPath
|
|
462
|
+
}) : void 0;
|
|
463
|
+
const inheritsParentMemoryMount = memoryDomain !== void 0 && memoryDomain === parent.scope.memoryDomain;
|
|
464
|
+
const withMemory = memoryDomain && !inheritsParentMemoryMount ? require_memory_afs.attachMemoryMount(withScratch, require_memory_afs.createMemoryProvider({
|
|
465
|
+
domain: memoryDomain,
|
|
466
|
+
storage: require_memory_afs.buildMemoryStorageForAfs(parent),
|
|
467
|
+
...require_memory_afs.buildMemoryIndexOptsForAfs(parent)
|
|
468
|
+
})) : withScratch;
|
|
469
|
+
const finalTools = memoryDomain ? ensureMemoryTool(withMessaging) : withMessaging;
|
|
470
|
+
const childBudget = deriveChildBudgetState(parent.scope.budget, options.childManifest.budget);
|
|
471
|
+
return attachScope(childBudget ? attachBudgetMount(withMemory, childBudget) : withMemory, {
|
|
472
|
+
session: childSession,
|
|
473
|
+
parentSession: parent.scope.session,
|
|
474
|
+
rootSession: parent.scope.rootSession,
|
|
475
|
+
chainDepth: nextDepth,
|
|
476
|
+
allowedPaths: finalTools.map((t) => t.path),
|
|
477
|
+
allowedTools: finalTools,
|
|
478
|
+
memoryDomain,
|
|
479
|
+
budget: childBudget
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
/** `memory: true` | `memory: { … }` both count; `false`/`undefined` do not. */
|
|
483
|
+
function isMemoryEnabled(value) {
|
|
484
|
+
return value === true || typeof value === "object" && value !== null;
|
|
485
|
+
}
|
|
486
|
+
const MEMORY_TOOL_PATH = "/memory/**";
|
|
487
|
+
function ensureMemoryTool(tools) {
|
|
488
|
+
if (tools.some((t) => t.path === MEMORY_TOOL_PATH || t.path === "/memory")) return tools;
|
|
489
|
+
return [...tools, {
|
|
490
|
+
path: MEMORY_TOOL_PATH,
|
|
491
|
+
ops: [
|
|
492
|
+
"read",
|
|
493
|
+
"list",
|
|
494
|
+
"exec"
|
|
495
|
+
]
|
|
496
|
+
}];
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* The scope descriptor's `session` may come from callers that tolerate path
|
|
500
|
+
* segments (e.g. `.../planner-0`). The scratch provider rejects separators
|
|
501
|
+
* and dots, so we collapse the caller-supplied id down to a bare token
|
|
502
|
+
* before handing it over.
|
|
503
|
+
*/
|
|
504
|
+
function sanitizeSessionForScratch(session) {
|
|
505
|
+
const trimmed = (session ?? "").replace(/\/+$/, "");
|
|
506
|
+
const cleaned = trimmed.slice(trimmed.lastIndexOf("/") + 1).replace(/\.\./g, "").replace(/\0/g, "");
|
|
507
|
+
return cleaned.length > 0 ? cleaned : "scope";
|
|
508
|
+
}
|
|
509
|
+
function ensureMessagingTool(tools) {
|
|
510
|
+
if (tools.some((t) => t.path === MESSAGING_TOOL_PATH || t.path === require_agent_messages_tools.MESSAGING_TOOLS_ROOT)) return tools;
|
|
511
|
+
return [...tools, {
|
|
512
|
+
path: MESSAGING_TOOL_PATH,
|
|
513
|
+
ops: ["exec"]
|
|
514
|
+
}];
|
|
515
|
+
}
|
|
516
|
+
function deriveDefaultChildSession(parentSession, memberPath) {
|
|
517
|
+
return `${parentSession}.${memberPath.split("/").filter(Boolean).pop() ?? "child"}.${Math.random().toString(36).slice(2, 8)}`;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Phase 2 target — serialize a scope for cross-process hand-off (MCP
|
|
521
|
+
* sandbox worker, code-agent runner, …). Always throws in Phase 0/1 so
|
|
522
|
+
* no caller is tempted to persist a partial descriptor before the sandbox
|
|
523
|
+
* boundary exists.
|
|
524
|
+
*/
|
|
525
|
+
function toJSON(_scope) {
|
|
526
|
+
throw new Error("AGENT_SCOPE_TOJSON_PHASE_2: scope serialization lands with the MCP sandbox (Phase 2)");
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
//#endregion
|
|
530
|
+
exports.CHAIN_DEPTH_HARD_CAP = CHAIN_DEPTH_HARD_CAP;
|
|
531
|
+
exports.ensureScopeWithMounts = ensureScopeWithMounts;
|
|
532
|
+
exports.normalizeManifestTools = normalizeManifestTools;
|
|
533
|
+
exports.projectForChild = projectForChild;
|
|
534
|
+
exports.resolveChildSession = resolveChildSession;
|
|
535
|
+
exports.resolveParentAgentScope = resolveParentAgentScope;
|
|
536
|
+
exports.rootAgentScope = rootAgentScope;
|
|
537
|
+
exports.runnerSession = runnerSession;
|
|
538
|
+
exports.toJSON = toJSON;
|