@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,313 @@
|
|
|
1
|
+
import { createBudgetTracker, resolveBudget } from "../agent-runners/budget.mjs";
|
|
2
|
+
import { formatRecallForPrompt, isHandoffReadThroughEnabled, isMemoryArchiveEnabled, recallForHandoff, wrapToolProgress } from "../agent-runners/memory-archive.mjs";
|
|
3
|
+
import { runAshAgent } from "../agent-runners/ash-runner.mjs";
|
|
4
|
+
import { provisionScratchViaAFS } from "../agent-runners/scratchpad-afs.mjs";
|
|
5
|
+
import { createHookDispatcher } from "../agent-runners/hooks.mjs";
|
|
6
|
+
import { mountManifestMemory } from "../agent-runners/memory-afs.mjs";
|
|
7
|
+
import { MESSAGING_TOOLS_GLOB, MESSAGING_TOOLS_ROOT } from "./agent-messages-tools.mjs";
|
|
8
|
+
import { normalizeManifestTools, resolveChildSession } from "./scoped-afs.mjs";
|
|
9
|
+
import { checkSpawnDepth, deriveChildSession } from "./session-hierarchy.mjs";
|
|
10
|
+
import { codeRunner } from "../agent-runners/code-runner.mjs";
|
|
11
|
+
import { createStreamProgressRouter, detectUISessionPath } from "../agent-runners/stream-router.mjs";
|
|
12
|
+
import { extractBlockletId } from "../agent-runners/system-prompt.mjs";
|
|
13
|
+
import { runTeamAgent } from "../agent-runners/team-runner.mjs";
|
|
14
|
+
import { createAgentActionHandlers } from "./agent-action.mjs";
|
|
15
|
+
import { runOrchestratorAgent } from "../agent-runners/orchestrator-runner.mjs";
|
|
16
|
+
import { makeNsLog } from "@aigne/afs";
|
|
17
|
+
|
|
18
|
+
//#region src/program/agent-runner-registry.ts
|
|
19
|
+
const log = makeNsLog("agent-runtime");
|
|
20
|
+
/**
|
|
21
|
+
* B10 — extract a filesystem-safe scratch key from a raw session id.
|
|
22
|
+
*
|
|
23
|
+
* The AI runner accepts either a bare id (`abc`) or a full session path
|
|
24
|
+
* (`/instance/.sessions/agent/abc`). Scratch paths must not contain separators,
|
|
25
|
+
* so we take the last non-empty path component.
|
|
26
|
+
*/
|
|
27
|
+
function scratchKeyFromSession(sessionId) {
|
|
28
|
+
const trimmed = sessionId.replace(/\/+$/, "");
|
|
29
|
+
const idx = trimmed.lastIndexOf("/");
|
|
30
|
+
return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
|
|
31
|
+
}
|
|
32
|
+
async function maybeProvisionScratch(afs, manifest, sessionId, runId) {
|
|
33
|
+
if (!manifest.scratch || !sessionId) return null;
|
|
34
|
+
const key = scratchKeyFromSession(sessionId);
|
|
35
|
+
if (!key) return null;
|
|
36
|
+
try {
|
|
37
|
+
return await provisionScratchViaAFS(afs, key, runId);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
log.warn(`[agent-runner] scratchpad provisioning failed for session=${key} runId=${runId}:`, err instanceof Error ? err.message : err);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function injectScratchPath(result, layout) {
|
|
44
|
+
const data = result.data ?? {};
|
|
45
|
+
data.scratch_path = layout.basePath;
|
|
46
|
+
const meta = data._meta && typeof data._meta === "object" ? data._meta : {};
|
|
47
|
+
meta.scratch_path = layout.basePath;
|
|
48
|
+
data._meta = meta;
|
|
49
|
+
result.data = data;
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the effective tool whitelist for a runner. Phase 6 collapsed the
|
|
54
|
+
* parent-tools fallback: `ctx.afs.scope.allowedTools` is the single source
|
|
55
|
+
* of truth (computed by `projectForChild`). Callers without a scope fall
|
|
56
|
+
* back to the manifest's own tools.
|
|
57
|
+
*/
|
|
58
|
+
function resolveEffectiveTools(context, childTools) {
|
|
59
|
+
const scope = context.afs.scope;
|
|
60
|
+
if (scope) return [...scope.allowedTools];
|
|
61
|
+
return childTools;
|
|
62
|
+
}
|
|
63
|
+
function withLifecycleHooks(runner) {
|
|
64
|
+
return async (input, context) => {
|
|
65
|
+
const blockletId = extractBlockletId(context.mountPath);
|
|
66
|
+
const scope = context.afs.scope;
|
|
67
|
+
const chainDepth = scope?.chainDepth ?? 0;
|
|
68
|
+
const dispatcher = createHookDispatcher(context.afs, context.manifest.hooks, {
|
|
69
|
+
mountPath: context.mountPath,
|
|
70
|
+
blockletId,
|
|
71
|
+
session: scope?.session ?? context.session,
|
|
72
|
+
chainDepth
|
|
73
|
+
});
|
|
74
|
+
const enrichedContext = {
|
|
75
|
+
...context,
|
|
76
|
+
hookDispatcher: dispatcher
|
|
77
|
+
};
|
|
78
|
+
await dispatcher.fireOnStart(input);
|
|
79
|
+
try {
|
|
80
|
+
const result = await runner(input, enrichedContext);
|
|
81
|
+
await dispatcher.fireOnSuccess(result);
|
|
82
|
+
return result;
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
85
|
+
await dispatcher.fireOnError({
|
|
86
|
+
code: "RUNNER_ERROR",
|
|
87
|
+
message
|
|
88
|
+
});
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const aiRunner = async (input, context) => {
|
|
94
|
+
const { manifest } = context;
|
|
95
|
+
const effectiveAfs = mountManifestMemory(context.afs, manifest.memory, context.mountPath);
|
|
96
|
+
const inputKey = manifest.inputKey ?? "message";
|
|
97
|
+
const task = String(input[inputKey] ?? "");
|
|
98
|
+
const callerBlockletId = extractBlockletId(context.mountPath);
|
|
99
|
+
const chain = context.chain ?? [];
|
|
100
|
+
checkSpawnDepth(chain, manifest.maxSpawnDepth);
|
|
101
|
+
const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(context.afs, context, deriveChildSession);
|
|
102
|
+
const tools = resolveEffectiveTools(context, normalizeManifestTools(manifest)).map((t) => ({
|
|
103
|
+
path: t.path,
|
|
104
|
+
...t.ops ? { ops: t.ops } : {},
|
|
105
|
+
...t.maxDepth != null ? { maxDepth: t.maxDepth } : {},
|
|
106
|
+
...t.exclude_actions ? { exclude_actions: t.exclude_actions } : {}
|
|
107
|
+
}));
|
|
108
|
+
const messagingPath = MESSAGING_TOOLS_GLOB;
|
|
109
|
+
if (!tools.some((t) => t.path === messagingPath || t.path === MESSAGING_TOOLS_ROOT)) tools.push({
|
|
110
|
+
path: messagingPath,
|
|
111
|
+
ops: ["exec"]
|
|
112
|
+
});
|
|
113
|
+
if (manifest.memory) {
|
|
114
|
+
if (!tools.some((t) => t.path === "/memory/**" || t.path === "/memory" || t.path.startsWith("/memory/"))) tools.push({
|
|
115
|
+
path: "/memory/**",
|
|
116
|
+
ops: [
|
|
117
|
+
"read",
|
|
118
|
+
"list",
|
|
119
|
+
"exec"
|
|
120
|
+
]
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const model = typeof manifest.model === "string" ? manifest.model : manifest.model ? `${manifest.model.provider}/${manifest.model.name}` : "/dev/ai/.actions/chat";
|
|
124
|
+
const session = sessionId ? sessionId.startsWith("/") ? sessionId : `/instance/.sessions/agent/${sessionId}` : void 0;
|
|
125
|
+
const scopeBudget = context.afs.scope?.budget;
|
|
126
|
+
const resolved = resolveBudget({
|
|
127
|
+
manifest: manifest.budget,
|
|
128
|
+
parentRemaining: scopeBudget ? Math.max(0, scopeBudget.limit - scopeBudget.consumed) : void 0
|
|
129
|
+
});
|
|
130
|
+
const tracker = createBudgetTracker(resolved);
|
|
131
|
+
let system;
|
|
132
|
+
if (manifest.instructions) try {
|
|
133
|
+
const instrPath = manifest.instructions.startsWith("/") ? manifest.instructions : `/packages/${manifest.instructions}`;
|
|
134
|
+
const r = await effectiveAfs.read(instrPath);
|
|
135
|
+
system = String(r?.data?.content ?? "");
|
|
136
|
+
if (!system.trim()) system = void 0;
|
|
137
|
+
} catch {}
|
|
138
|
+
if (context.systemAppend) system = system ? `${system}\n\n${context.systemAppend}` : context.systemAppend;
|
|
139
|
+
else if (isHandoffReadThroughEnabled(manifest.memory) && !context.afs?.scope?.memoryDomain) {
|
|
140
|
+
const manifestDomain = manifest.memory && typeof manifest.memory === "object" ? manifest.memory.domain : void 0;
|
|
141
|
+
if (manifestDomain) {
|
|
142
|
+
const appendix = formatRecallForPrompt(await recallForHandoff({
|
|
143
|
+
afs: effectiveAfs,
|
|
144
|
+
domain: manifestDomain
|
|
145
|
+
}));
|
|
146
|
+
if (appendix) system = system ? `${system}\n\n${appendix}` : appendix;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const execArgs = {
|
|
150
|
+
task,
|
|
151
|
+
model,
|
|
152
|
+
tools,
|
|
153
|
+
budget: {
|
|
154
|
+
max_rounds: resolved.maxRounds,
|
|
155
|
+
total_tokens: resolved.totalTokens
|
|
156
|
+
},
|
|
157
|
+
session,
|
|
158
|
+
system,
|
|
159
|
+
skill_paths: manifest.skillPaths,
|
|
160
|
+
tool_choice: manifest.toolChoice,
|
|
161
|
+
exec_context: callerBlockletId ? { from: callerBlockletId } : void 0,
|
|
162
|
+
_scope_afs: effectiveAfs,
|
|
163
|
+
_parent_session: scopedParentSession,
|
|
164
|
+
_chain: [...chain, sessionId ?? "root"],
|
|
165
|
+
_abort_signal: tracker.signal
|
|
166
|
+
};
|
|
167
|
+
const streamNodeId = typeof input._stream_node_id === "string" ? input._stream_node_id : void 0;
|
|
168
|
+
const autoRouter = !input._on_tool_progress ? createStreamProgressRouter({
|
|
169
|
+
afs: effectiveAfs,
|
|
170
|
+
sessionPath: detectUISessionPath(session),
|
|
171
|
+
nodeId: streamNodeId
|
|
172
|
+
}) : null;
|
|
173
|
+
const baseProgress = input._on_tool_progress;
|
|
174
|
+
const skillStarts = !!(context.hookDispatcher && (manifest.hooks?.onSkillStart || manifest.hooks?.onSkillEnd)) ? /* @__PURE__ */ new Map() : null;
|
|
175
|
+
const fireSkillHooks = skillStarts ? (event) => {
|
|
176
|
+
const dispatcher = context.hookDispatcher;
|
|
177
|
+
const calls = event.calls;
|
|
178
|
+
if (!calls) return;
|
|
179
|
+
if (event.type === "tool_start") for (const c of calls) {
|
|
180
|
+
skillStarts.set(c.id, Date.now());
|
|
181
|
+
dispatcher.fireOnSkillStart(c.tool, c.args ?? {});
|
|
182
|
+
}
|
|
183
|
+
else if (event.type === "tool_result") for (const c of calls) {
|
|
184
|
+
const started = skillStarts.get(c.id);
|
|
185
|
+
const durationMs = started ? Date.now() - started : 0;
|
|
186
|
+
skillStarts.delete(c.id);
|
|
187
|
+
dispatcher.fireOnSkillEnd(c.tool, {
|
|
188
|
+
status: c.status === "error" ? "error" : "ok",
|
|
189
|
+
...c.result !== void 0 ? { result: c.result } : {},
|
|
190
|
+
...c.error !== void 0 ? { error: c.error } : {},
|
|
191
|
+
durationMs
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
} : null;
|
|
195
|
+
const listeners = [];
|
|
196
|
+
if (fireSkillHooks) listeners.push(fireSkillHooks);
|
|
197
|
+
if (baseProgress) listeners.push(baseProgress);
|
|
198
|
+
else if (autoRouter) listeners.push((event) => autoRouter.onProgress(event));
|
|
199
|
+
let composedProgress;
|
|
200
|
+
if (listeners.length === 1) composedProgress = listeners[0];
|
|
201
|
+
else if (listeners.length > 1) composedProgress = (event) => {
|
|
202
|
+
for (const l of listeners) l(event);
|
|
203
|
+
};
|
|
204
|
+
if (isMemoryArchiveEnabled(manifest.memory)) composedProgress = wrapToolProgress(composedProgress, {
|
|
205
|
+
afs: effectiveAfs,
|
|
206
|
+
session: sessionId ?? "default"
|
|
207
|
+
});
|
|
208
|
+
if (composedProgress) execArgs._on_tool_progress = composedProgress;
|
|
209
|
+
if (input.on_progress) execArgs.on_progress = input.on_progress;
|
|
210
|
+
if (typeof input._ui_session === "string") execArgs._ui_session = input._ui_session;
|
|
211
|
+
for (const [key, value] of Object.entries(input)) {
|
|
212
|
+
if (key === inputKey) continue;
|
|
213
|
+
if (key.startsWith("_")) continue;
|
|
214
|
+
if (key in execArgs) continue;
|
|
215
|
+
execArgs[key] = value;
|
|
216
|
+
}
|
|
217
|
+
const runId = crypto.randomUUID();
|
|
218
|
+
const scratchLayout = await maybeProvisionScratch(effectiveAfs, manifest, sessionId, runId);
|
|
219
|
+
if (scratchLayout) {
|
|
220
|
+
execArgs._scratch_path = scratchLayout.basePath;
|
|
221
|
+
execArgs._scratch_run_id = runId;
|
|
222
|
+
}
|
|
223
|
+
const result = await effectiveAfs.exec("/dev/agent/.actions/run", execArgs, {});
|
|
224
|
+
if (autoRouter) await autoRouter.flush();
|
|
225
|
+
const tokensUsed = result?.data?.total_tokens ?? result?.data?._meta?.tokens_used ?? 0;
|
|
226
|
+
tracker.consumeTokens(tokensUsed);
|
|
227
|
+
if (resolved.warnings.length > 0) {
|
|
228
|
+
const data = result?.data ?? {};
|
|
229
|
+
const meta = data._meta ?? {};
|
|
230
|
+
meta.warnings = [...Array.isArray(meta.warnings) ? meta.warnings : [], ...resolved.warnings];
|
|
231
|
+
data._meta = meta;
|
|
232
|
+
}
|
|
233
|
+
if (scratchLayout) injectScratchPath(result, scratchLayout);
|
|
234
|
+
return result;
|
|
235
|
+
};
|
|
236
|
+
const ashRunner = async (input, context) => {
|
|
237
|
+
const { manifest } = context;
|
|
238
|
+
const effectiveAfs = context.afs;
|
|
239
|
+
const chain = context.chain ?? [];
|
|
240
|
+
checkSpawnDepth(chain, manifest.maxSpawnDepth);
|
|
241
|
+
const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(context.afs, context, deriveChildSession);
|
|
242
|
+
return await runAshAgent({
|
|
243
|
+
afs: effectiveAfs,
|
|
244
|
+
manifest,
|
|
245
|
+
input,
|
|
246
|
+
session: sessionId,
|
|
247
|
+
parentSession: scopedParentSession,
|
|
248
|
+
chain: [...chain, sessionId ?? "root"],
|
|
249
|
+
mountPath: context.mountPath
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
const teamRunner = async (input, context) => {
|
|
253
|
+
const { manifest } = context;
|
|
254
|
+
const chain = context.chain ?? [];
|
|
255
|
+
checkSpawnDepth(chain, manifest.maxSpawnDepth);
|
|
256
|
+
const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(context.afs, context, deriveChildSession);
|
|
257
|
+
return await runTeamAgent(input, {
|
|
258
|
+
...context,
|
|
259
|
+
session: sessionId,
|
|
260
|
+
parentSession: scopedParentSession,
|
|
261
|
+
chain: [...chain, sessionId ?? "root"]
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
const orchestratorRunner = async (input, context) => {
|
|
265
|
+
const { manifest } = context;
|
|
266
|
+
const chain = context.chain ?? [];
|
|
267
|
+
checkSpawnDepth(chain, manifest.maxSpawnDepth);
|
|
268
|
+
const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(context.afs, context, deriveChildSession);
|
|
269
|
+
return await runOrchestratorAgent(input, {
|
|
270
|
+
...context,
|
|
271
|
+
session: sessionId,
|
|
272
|
+
parentSession: scopedParentSession,
|
|
273
|
+
chain: [...chain, sessionId ?? "root"]
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
const runners = {
|
|
277
|
+
ai: withLifecycleHooks(aiRunner),
|
|
278
|
+
ash: withLifecycleHooks(ashRunner),
|
|
279
|
+
team: withLifecycleHooks(teamRunner),
|
|
280
|
+
orchestrator: withLifecycleHooks(orchestratorRunner),
|
|
281
|
+
code: withLifecycleHooks(codeRunner)
|
|
282
|
+
};
|
|
283
|
+
function getRunnerForType(type) {
|
|
284
|
+
const runner = runners[type];
|
|
285
|
+
if (!runner) throw new Error(`RUNNER_NOT_IMPLEMENTED: agent type "${type}" is not yet supported`);
|
|
286
|
+
return runner;
|
|
287
|
+
}
|
|
288
|
+
function registerAgentActions(runtimeAFS, manifest, mountPath, options) {
|
|
289
|
+
const handlers = createAgentActionHandlers(manifest, mountPath, { actionPrefix: options?.actionPrefix });
|
|
290
|
+
const afs = runtimeAFS;
|
|
291
|
+
if (typeof afs.registerCustomAction !== "function") return;
|
|
292
|
+
const prefix = options?.actionPrefix;
|
|
293
|
+
const runKey = prefix ? `${prefix}-run` : "run";
|
|
294
|
+
const cancelKey = prefix ? `${prefix}-cancel` : "cancel";
|
|
295
|
+
const statusKey = prefix ? `${prefix}-status` : "status";
|
|
296
|
+
afs.registerCustomAction(runKey, handlers.run.entry, async (args) => {
|
|
297
|
+
return handlers.run.handler(args, {
|
|
298
|
+
afs: runtimeAFS,
|
|
299
|
+
mountPath,
|
|
300
|
+
manifest
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
afs.registerCustomAction(cancelKey, handlers.cancel.entry, async (args) => {
|
|
304
|
+
return handlers.cancel.handler(args);
|
|
305
|
+
});
|
|
306
|
+
afs.registerCustomAction(statusKey, handlers.status.entry, async (args) => {
|
|
307
|
+
return handlers.status.handler(args);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
//#endregion
|
|
312
|
+
export { getRunnerForType, registerAgentActions };
|
|
313
|
+
//# sourceMappingURL=agent-runner-registry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-runner-registry.mjs","names":[],"sources":["../../src/program/agent-runner-registry.ts"],"sourcesContent":["/**\n * Agent runner registry — dispatches agent execution by manifest type.\n *\n * S2 wires only `type: ai`; other types throw RUNNER_NOT_IMPLEMENTED\n * until their respective phases land (S6 for team, etc.).\n */\n\nimport type { AFSExecResult, AFSRoot, AgentManifest } from \"@aigne/afs\";\nimport { makeNsLog } from \"@aigne/afs\";\nimport { runAshAgent } from \"../agent-runners/ash-runner.js\";\nimport { createBudgetTracker, resolveBudget } from \"../agent-runners/budget.js\";\nimport { codeRunner } from \"../agent-runners/code-runner.js\";\nimport { createHookDispatcher, type HookDispatcher } from \"../agent-runners/hooks.js\";\nimport { mountManifestMemory } from \"../agent-runners/memory-afs.js\";\nimport {\n formatRecallForPrompt,\n isHandoffReadThroughEnabled,\n isMemoryArchiveEnabled,\n recallForHandoff,\n type ToolProgressEvent,\n wrapToolProgress,\n} from \"../agent-runners/memory-archive.js\";\nimport { runOrchestratorAgent } from \"../agent-runners/orchestrator-runner.js\";\nimport { type AFSScratchLayout, provisionScratchViaAFS } from \"../agent-runners/scratchpad-afs.js\";\nimport { createStreamProgressRouter, detectUISessionPath } from \"../agent-runners/stream-router.js\";\nimport { extractBlockletId } from \"../agent-runners/system-prompt.js\";\nimport { runTeamAgent } from \"../agent-runners/team-runner.js\";\nimport { createAgentActionHandlers } from \"./agent-action.js\";\nimport { MESSAGING_TOOLS_GLOB, MESSAGING_TOOLS_ROOT } from \"./agent-messages-tools.js\";\nimport { type AgentScope, normalizeManifestTools, resolveChildSession } from \"./scoped-afs.js\";\nimport { checkSpawnDepth, deriveChildSession } from \"./session-hierarchy.js\";\n\nconst log = makeNsLog(\"agent-runtime\");\n\n/**\n * Runner context — shape consumed by every agent runner.\n *\n * Phase 6 collapsed the grab-bag of parent-projection fields now that\n * `AgentScope` carries the equivalent state:\n *\n * - `context.afs.scope.allowedTools` — tool whitelist\n * - `context.afs.scope.budget` — per-scope budget limit/consumed\n * - `context.afs.scope.memoryDomain` — per-scope memory provider\n * - `context.afs.scope.chainDepth` — spawn-chain depth counter\n *\n * The remaining `mountPath` / `session` / `parentSession` / `chain` /\n * `systemAppend` fields still live on the context because their natural\n * home on `AgentScope` hasn't been added yet — see the follow-up note in\n * `planning/agent-runtime-afs-first/tasks.md` (P7: scope schema additions).\n */\nexport interface RunnerContext {\n afs: AFSRoot;\n /** Blocklet mount root — used for instructions / script path resolution. */\n mountPath: string;\n manifest: AgentManifest;\n /** @deprecated (P7) read from `ctx.afs.scope.session` once scope.session is the only source. */\n session?: string;\n /** @deprecated (P7) read from `ctx.afs.scope.parentSession`. */\n parentSession?: string;\n /** @deprecated (P7) derive from `ctx.afs.scope.chainDepth`. */\n chain?: string[];\n hookDispatcher?: HookDispatcher;\n /** @deprecated (P7) caller-supplied system-prompt suffix; moves to scope in P7. */\n systemAppend?: string;\n}\n\n/**\n * B10 — extract a filesystem-safe scratch key from a raw session id.\n *\n * The AI runner accepts either a bare id (`abc`) or a full session path\n * (`/instance/.sessions/agent/abc`). Scratch paths must not contain separators,\n * so we take the last non-empty path component.\n */\nfunction scratchKeyFromSession(sessionId: string): string {\n const trimmed = sessionId.replace(/\\/+$/, \"\");\n const idx = trimmed.lastIndexOf(\"/\");\n return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;\n}\n\nasync function maybeProvisionScratch(\n afs: AFSRoot,\n manifest: AgentManifest,\n sessionId: string | undefined,\n runId: string,\n): Promise<AFSScratchLayout | null> {\n if (!manifest.scratch || !sessionId) return null;\n const key = scratchKeyFromSession(sessionId);\n if (!key) return null;\n try {\n return await provisionScratchViaAFS(afs, key, runId);\n } catch (err) {\n // Provisioning failures must not crash the run — surface via warnings later.\n log.warn(\n `[agent-runner] scratchpad provisioning failed for session=${key} runId=${runId}:`,\n err instanceof Error ? err.message : err,\n );\n return null;\n }\n}\n\nfunction injectScratchPath(result: AFSExecResult, layout: AFSScratchLayout): AFSExecResult {\n const data = ((result as any).data ?? {}) as Record<string, unknown>;\n data.scratch_path = layout.basePath;\n const meta = (data._meta && typeof data._meta === \"object\" ? data._meta : {}) as Record<\n string,\n unknown\n >;\n meta.scratch_path = layout.basePath;\n data._meta = meta;\n (result as any).data = data;\n return result;\n}\n\n/**\n * Resolve the effective tool whitelist for a runner. Phase 6 collapsed the\n * parent-tools fallback: `ctx.afs.scope.allowedTools` is the single source\n * of truth (computed by `projectForChild`). Callers without a scope fall\n * back to the manifest's own tools.\n */\nfunction resolveEffectiveTools(\n context: RunnerContext,\n childTools: import(\"@aigne/afs-ash\").ToolEntry[],\n): import(\"@aigne/afs-ash\").ToolEntry[] {\n const scope = (context.afs as AgentScope).scope;\n if (scope) return [...scope.allowedTools];\n return childTools;\n}\n\nexport type AgentRunner = (\n input: Record<string, unknown>,\n context: RunnerContext,\n) => Promise<AFSExecResult>;\n\nfunction withLifecycleHooks(runner: AgentRunner): AgentRunner {\n return async (input, context) => {\n const blockletId = extractBlockletId(context.mountPath);\n // Phase 6 — hook chain depth follows the scope chain; scope-less callers\n // (legacy direct RunnerContext construction) default to root depth 0.\n const scope = (context.afs as AgentScope).scope;\n const chainDepth = scope?.chainDepth ?? 0;\n\n const dispatcher = createHookDispatcher(context.afs, context.manifest.hooks as any, {\n mountPath: context.mountPath,\n blockletId,\n session: scope?.session ?? context.session,\n chainDepth,\n });\n\n const enrichedContext: RunnerContext = {\n ...context,\n hookDispatcher: dispatcher,\n };\n\n await dispatcher.fireOnStart(input);\n try {\n const result = await runner(input, enrichedContext);\n await dispatcher.fireOnSuccess(result);\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await dispatcher.fireOnError({ code: \"RUNNER_ERROR\", message });\n throw err;\n }\n };\n}\n\nconst aiRunner: AgentRunner = async (input, context) => {\n const { manifest } = context;\n // Bootstrap the scope's `/memory/` mount when this top-level AI agent\n // declares `memory:` and the parent didn't already attach one. The\n // Mount /memory/ when the manifest declares memory. `mountManifestMemory`\n // is the shared unified helper used by all surfaces (chat, terminal, …);\n // it skips when the caller's AFS already carries a scope memory domain.\n const effectiveAfs = mountManifestMemory(context.afs, manifest.memory, context.mountPath);\n const inputKey = manifest.inputKey ?? \"message\";\n const task = String(input[inputKey] ?? \"\");\n const callerBlockletId = extractBlockletId(context.mountPath);\n\n const chain = context.chain ?? [];\n checkSpawnDepth(chain, manifest.maxSpawnDepth);\n\n // Phase 5 — session/parentSession come from scope first (legacy context\n // fields only as fallback while scope.mountPath/session fully lands). When\n // both are set, the child id is derived from the parent.\n const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(\n context.afs,\n context,\n deriveChildSession,\n );\n\n const childTools = normalizeManifestTools(manifest);\n const tools = resolveEffectiveTools(context, childTools).map((t) => ({\n path: t.path,\n ...(t.ops ? { ops: t.ops } : {}),\n ...(t.maxDepth != null ? { maxDepth: t.maxDepth } : {}),\n ...(t.exclude_actions ? { exclude_actions: t.exclude_actions } : {}),\n }));\n\n // B32: always surface built-in messaging tools (agent_post_message /\n // agent_read_messages) to the LLM via the MCP tool catalog. When the\n // scope came from `projectForChild`, `/proc/messaging/tools/*` is already\n // in `allowedTools`; this fallback covers callers that hand us a bare\n // AFS without an attached scope.\n const messagingPath = MESSAGING_TOOLS_GLOB;\n if (!tools.some((t) => t.path === messagingPath || t.path === MESSAGING_TOOLS_ROOT)) {\n tools.push({ path: messagingPath, ops: [\"exec\"] });\n }\n\n // AFS conformance: top-level AI agents with `manifest.memory` enabled\n // get standard read/list/exec on `/memory/**` so the agent can both\n // observe (`afs_list /memory/<domain>`) and operate (`recall`,\n // `remember`) the memory store. For child scopes, `projectForChild`\n // (scoped-afs.ts → ensureMemoryTool) does the same; this branch covers\n // the top-level path that bypasses scope projection.\n //\n // Without this, blocklet authors must explicitly list `/memory/**` in\n // agent.json `tools[]` (and forgetting to do so silently breaks\n // inspection — the agent loops on questions like \"what's stored?\"\n // because recall is similarity search, not enumeration).\n if (manifest.memory) {\n const hasMemoryTool = tools.some(\n (t) => t.path === \"/memory/**\" || t.path === \"/memory\" || t.path.startsWith(\"/memory/\"),\n );\n if (!hasMemoryTool) {\n tools.push({ path: \"/memory/**\", ops: [\"read\", \"list\", \"exec\"] });\n }\n }\n\n const model =\n typeof manifest.model === \"string\"\n ? manifest.model\n : manifest.model\n ? `${manifest.model.provider}/${manifest.model.name}`\n : \"/dev/ai/.actions/chat\";\n\n // Accept either a bare sessionId (\"abc123\") or a full AFS path\n // (\"/instance/sessions/foo/abc\"). If caller already provided a path, use it\n // verbatim; otherwise prepend the default session directory.\n const session = sessionId\n ? sessionId.startsWith(\"/\")\n ? sessionId\n : `/instance/.sessions/agent/${sessionId}`\n : undefined;\n\n // Phase 6 — budget comes exclusively from manifest + parent scope.\n // Child clamps happen inside `projectForChild` via `scope.budget` and\n // the exec middleware attached by `attachBudgetMount`.\n const scopeBudget = (context.afs as AgentScope).scope?.budget;\n const resolved = resolveBudget({\n manifest: manifest.budget,\n parentRemaining: scopeBudget\n ? Math.max(0, scopeBudget.limit - scopeBudget.consumed)\n : undefined,\n });\n const tracker = createBudgetTracker(resolved);\n\n // Load system prompt from manifest.instructions path (relative to /packages)\n let system: string | undefined;\n if (manifest.instructions) {\n try {\n const instrPath = manifest.instructions.startsWith(\"/\")\n ? manifest.instructions\n : `/packages/${manifest.instructions}`;\n const r = await effectiveAfs.read!(instrPath);\n system = String(r?.data?.content ?? \"\");\n if (!system.trim()) system = undefined;\n } catch {\n // instructions file not found — proceed without system prompt\n }\n }\n\n // G2 — append caller-supplied system suffix (e.g. handoff read-through\n // appendix) to the rendered system prompt before exec. ash's agent-run\n // only consumes `args.system`, so merging here is the only point where\n // the appendix actually reaches the LLM.\n if (context.systemAppend) {\n system = system ? `${system}\\n\\n${context.systemAppend}` : context.systemAppend;\n } else if (\n isHandoffReadThroughEnabled(manifest.memory) &&\n !(context.afs as { scope?: { memoryDomain?: string } } | undefined)?.scope?.memoryDomain\n ) {\n // Top-level single-agent recall. Mirrors the team-runner's G2 step\n // (`team-runner.ts:230`) for the case where there's no parent to\n // do it. Gated on:\n //\n // 1. `systemAppend` unset — a team / orchestrator parent owns\n // recall when set; doing it again would duplicate context.\n // 2. No `scope.memoryDomain` on `context.afs` — that field is\n // stamped by `projectForChild` / `ensureScopeWithMounts`\n // whenever a parent runner has already taken responsibility\n // for this iteration's recall. When set, we trust the parent\n // even if they happened to pass `systemAppend: undefined`\n // because the recall produced an empty appendix.\n //\n // Without this scope check, team-member dispatches that come from\n // a fresh-memory loop entry (where the team-runner's appendix is\n // empty) would each do their OWN recall mid-loop, surfacing\n // accumulated archives from prior iterations and biasing the\n // convergence pattern the team-runner intentionally bounded with\n // a single read-once-per-loop step.\n const manifestDomain =\n manifest.memory && typeof manifest.memory === \"object\"\n ? (manifest.memory as { domain?: string }).domain\n : undefined;\n if (manifestDomain) {\n const recalled = await recallForHandoff({ afs: effectiveAfs, domain: manifestDomain });\n const appendix = formatRecallForPrompt(recalled);\n if (appendix) {\n system = system ? `${system}\\n\\n${appendix}` : appendix;\n }\n }\n }\n\n const execArgs: Record<string, unknown> = {\n task,\n model,\n tools,\n budget: {\n max_rounds: resolved.maxRounds,\n total_tokens: resolved.totalTokens,\n },\n session,\n system,\n skill_paths: manifest.skillPaths,\n tool_choice: manifest.toolChoice,\n // B32: caller identity forwarded to tool dispatch. agent-run injects\n // `from` into /proc/messaging/tools/* calls so the LLM never forges a\n // sender. LLM-supplied values still win (normal execContext precedence).\n exec_context: callerBlockletId ? { from: callerBlockletId } : undefined,\n // @deprecated (P7) scope handle still forwarded to the ash provider for\n // agent-run sub-tool routing; removed when the provider reads scope via\n // `afs.scope` directly.\n _scope_afs: effectiveAfs,\n _parent_session: scopedParentSession,\n _chain: [...chain, sessionId ?? \"root\"],\n _abort_signal: tracker.signal,\n };\n\n // Phase 2 — when the caller session lives inside the UI provider, auto-route\n // LLM streaming deltas to `<session>/.actions/aup_patch` so the user sees\n // tokens as they arrive. Caller-supplied `_on_tool_progress` always wins.\n const streamNodeId =\n typeof input._stream_node_id === \"string\" ? input._stream_node_id : undefined;\n const autoRouter = !input._on_tool_progress\n ? createStreamProgressRouter({\n afs: effectiveAfs,\n sessionPath: detectUISessionPath(session),\n nodeId: streamNodeId,\n })\n : null;\n\n const baseProgress = input._on_tool_progress as\n | ((event: Record<string, unknown>) => void)\n | undefined;\n\n const skillHooksActive = !!(\n context.hookDispatcher &&\n (manifest.hooks?.onSkillStart || manifest.hooks?.onSkillEnd)\n );\n // Pair tool_start/tool_result events by call.id to compute durationMs.\n const skillStarts = skillHooksActive ? new Map<string, number>() : null;\n const fireSkillHooks = skillStarts\n ? (event: Record<string, unknown>) => {\n const dispatcher = context.hookDispatcher!;\n const calls = event.calls as\n | Array<{\n id: string;\n tool: string;\n args?: Record<string, unknown>;\n status: string;\n result?: unknown;\n error?: string;\n }>\n | undefined;\n if (!calls) return;\n if (event.type === \"tool_start\") {\n for (const c of calls) {\n skillStarts.set(c.id, Date.now());\n void dispatcher.fireOnSkillStart(c.tool, c.args ?? {});\n }\n } else if (event.type === \"tool_result\") {\n for (const c of calls) {\n const started = skillStarts.get(c.id);\n const durationMs = started ? Date.now() - started : 0;\n skillStarts.delete(c.id);\n void dispatcher.fireOnSkillEnd(c.tool, {\n status: c.status === \"error\" ? \"error\" : \"ok\",\n ...(c.result !== undefined ? { result: c.result } : {}),\n ...(c.error !== undefined ? { error: c.error } : {}),\n durationMs,\n });\n }\n }\n }\n : null;\n\n const listeners: Array<(event: Record<string, unknown>) => void> = [];\n if (fireSkillHooks) listeners.push(fireSkillHooks);\n if (baseProgress) listeners.push(baseProgress);\n else if (autoRouter)\n listeners.push((event) =>\n autoRouter.onProgress(event as { type: string; round?: number; text?: string }),\n );\n let composedProgress: ((event: Record<string, unknown>) => void) | undefined;\n if (listeners.length === 1) composedProgress = listeners[0];\n else if (listeners.length > 1)\n composedProgress = (event: Record<string, unknown>) => {\n for (const l of listeners) l(event);\n };\n\n // G1 — wrap composed progress with `wrapToolProgress` so every completed\n // (non-self) tool call fires a fire-and-forget archive to the scope-local\n // memory provider. Default-on when manifest.memory is enabled; only\n // `archiveTools: false` opts out.\n if (isMemoryArchiveEnabled(manifest.memory)) {\n composedProgress = wrapToolProgress(\n composedProgress as ((event: ToolProgressEvent) => void) | undefined,\n {\n afs: effectiveAfs,\n session: sessionId ?? \"default\",\n },\n ) as (event: Record<string, unknown>) => void;\n }\n if (composedProgress) execArgs._on_tool_progress = composedProgress;\n // Forward path-based progress callback — agent-run internally reads\n // `on_progress` (snake_case) and maps it to params.onProgress.\n if (input.on_progress) {\n execArgs.on_progress = input.on_progress;\n }\n // Forward the UI surface id for ask_user routing. `_`-prefixed fields are\n // skipped by the generic pass-through below, so forward it explicitly —\n // orchestration uses `_ui_session` to route an ask back to the originating\n // terminal/chat surface.\n if (typeof input._ui_session === \"string\") {\n execArgs._ui_session = input._ui_session;\n }\n\n // Forward any additional user-provided fields (e.g. `priority`, `context`)\n // that aren't reserved execArgs keys. This lets callers pass arbitrary\n // metadata through to the agent's environment alongside the task message.\n for (const [key, value] of Object.entries(input)) {\n if (key === inputKey) continue;\n if (key.startsWith(\"_\")) continue;\n if (key in execArgs) continue;\n execArgs[key] = value;\n }\n\n // Memory now flows through the scope's `/memory/*` mount (Phase 3);\n // domain is baked into the provider instance rather than smuggled per\n // call.\n\n // B10 — provision scratchpad under /modules/memory/runs/<session>/subruns/<runId>/\n // when `scratch: true` is set on the manifest. Templates and messaging tools\n // read this path from execArgs._scratch_* below.\n const runId = crypto.randomUUID();\n const scratchLayout = await maybeProvisionScratch(effectiveAfs, manifest, sessionId, runId);\n if (scratchLayout) {\n execArgs._scratch_path = scratchLayout.basePath;\n execArgs._scratch_run_id = runId;\n }\n\n const result = await effectiveAfs.exec!(\"/dev/agent/.actions/run\", execArgs, {});\n\n if (autoRouter) await autoRouter.flush();\n\n const tokensUsed =\n (result as any)?.data?.total_tokens ?? (result as any)?.data?._meta?.tokens_used ?? 0;\n tracker.consumeTokens(tokensUsed);\n\n if (resolved.warnings.length > 0) {\n const data = (result as any)?.data ?? {};\n const meta = data._meta ?? {};\n const existing = Array.isArray(meta.warnings) ? meta.warnings : [];\n meta.warnings = [...existing, ...resolved.warnings];\n data._meta = meta;\n }\n\n if (scratchLayout) injectScratchPath(result, scratchLayout);\n\n return result;\n};\n\nconst ashRunner: AgentRunner = async (input, context) => {\n const { manifest } = context;\n const effectiveAfs = context.afs;\n\n const chain = context.chain ?? [];\n checkSpawnDepth(chain, manifest.maxSpawnDepth);\n\n const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(\n context.afs,\n context,\n deriveChildSession,\n );\n\n const result = await runAshAgent({\n afs: effectiveAfs,\n manifest,\n input,\n session: sessionId,\n parentSession: scopedParentSession,\n chain: [...chain, sessionId ?? \"root\"],\n mountPath: context.mountPath,\n });\n\n return result as unknown as AFSExecResult;\n};\n\nconst teamRunner: AgentRunner = async (input, context) => {\n const { manifest } = context;\n\n const chain = context.chain ?? [];\n checkSpawnDepth(chain, manifest.maxSpawnDepth);\n\n const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(\n context.afs,\n context,\n deriveChildSession,\n );\n\n const result = await runTeamAgent(input, {\n ...context,\n session: sessionId,\n parentSession: scopedParentSession,\n chain: [...chain, sessionId ?? \"root\"],\n });\n\n return result as unknown as AFSExecResult;\n};\n\nconst orchestratorRunner: AgentRunner = async (input, context) => {\n const { manifest } = context;\n\n const chain = context.chain ?? [];\n checkSpawnDepth(chain, manifest.maxSpawnDepth);\n\n const { session: sessionId, parentSession: scopedParentSession } = resolveChildSession(\n context.afs,\n context,\n deriveChildSession,\n );\n\n const result = await runOrchestratorAgent(input, {\n ...context,\n session: sessionId,\n parentSession: scopedParentSession,\n chain: [...chain, sessionId ?? \"root\"],\n });\n\n return result as unknown as AFSExecResult;\n};\n\nconst runners: Record<string, AgentRunner> = {\n ai: withLifecycleHooks(aiRunner),\n ash: withLifecycleHooks(ashRunner),\n team: withLifecycleHooks(teamRunner),\n orchestrator: withLifecycleHooks(orchestratorRunner),\n code: withLifecycleHooks(codeRunner),\n};\n\nexport function getRunnerForType(type: string): AgentRunner {\n const runner = runners[type];\n if (!runner) {\n throw new Error(`RUNNER_NOT_IMPLEMENTED: agent type \"${type}\" is not yet supported`);\n }\n return runner;\n}\n\n/**\n * Options for `registerAgentActions`.\n *\n * `actionPrefix` lets one blocklet's runtime AFS host many independent\n * agents (e.g. nested manifests under `agents/<n>/`). Each prefix\n * registers its own `${prefix}-run`/`${prefix}-cancel`/`${prefix}-status`\n * customAction keys, so they coexist without colliding on the bare names.\n */\nexport interface RegisterAgentActionsOptions {\n actionPrefix?: string;\n}\n\nexport function registerAgentActions(\n runtimeAFS: AFSRoot,\n manifest: AgentManifest,\n mountPath: string,\n options?: RegisterAgentActionsOptions,\n): void {\n const handlers = createAgentActionHandlers(manifest, mountPath, {\n actionPrefix: options?.actionPrefix,\n });\n const afs = runtimeAFS as any;\n\n if (typeof afs.registerCustomAction !== \"function\") return;\n\n const prefix = options?.actionPrefix;\n const runKey = prefix ? `${prefix}-run` : \"run\";\n const cancelKey = prefix ? `${prefix}-cancel` : \"cancel\";\n const statusKey = prefix ? `${prefix}-status` : \"status\";\n\n afs.registerCustomAction(runKey, handlers.run.entry, async (args: Record<string, unknown>) => {\n return handlers.run.handler(args, { afs: runtimeAFS, mountPath, manifest });\n });\n\n afs.registerCustomAction(\n cancelKey,\n handlers.cancel.entry,\n async (args: Record<string, unknown>) => {\n return handlers.cancel.handler(args);\n },\n );\n\n afs.registerCustomAction(\n statusKey,\n handlers.status.entry,\n async (args: Record<string, unknown>) => {\n return handlers.status.handler(args);\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
let ufo = require("ufo");
|
|
2
|
+
let _aigne_afs = require("@aigne/afs");
|
|
3
|
+
|
|
4
|
+
//#region src/program/agent-subscribe.ts
|
|
5
|
+
const log = (0, _aigne_afs.makeNsLog)("agent-runtime");
|
|
6
|
+
const SELF_TOKEN = "<self>";
|
|
7
|
+
const DEFAULT_EVENT = "afs:write";
|
|
8
|
+
const DEFAULT_DISPATCH = ".actions/run";
|
|
9
|
+
const DEFAULT_INPUT_KEY = "message";
|
|
10
|
+
const NOOP_HANDLE = {
|
|
11
|
+
close: () => {},
|
|
12
|
+
settled: () => Promise.resolve()
|
|
13
|
+
};
|
|
14
|
+
function registerAgentSubscribes(opts) {
|
|
15
|
+
const { afs, manifest, mountPath } = opts;
|
|
16
|
+
const subscribeList = manifest.subscribe ?? [];
|
|
17
|
+
if (subscribeList.length === 0) return NOOP_HANDLE;
|
|
18
|
+
if (!afs.subscribe) throw new Error("afs.subscribe not available for agent-subscribe registration");
|
|
19
|
+
if (!opts.dispatch && !afs.exec) throw new Error("afs.exec not available for subscribe dispatch");
|
|
20
|
+
const dispatch = opts.dispatch ?? ((path, args) => afs.exec(path, args, {}));
|
|
21
|
+
const blockletId = mountPath.split("/").filter(Boolean).at(-1) ?? "";
|
|
22
|
+
const pending = /* @__PURE__ */ new Set();
|
|
23
|
+
const unsubs = [];
|
|
24
|
+
for (const entry of subscribeList) {
|
|
25
|
+
const resolvedPath = entry.path.split(SELF_TOKEN).join(blockletId);
|
|
26
|
+
const eventType = entry.event ?? DEFAULT_EVENT;
|
|
27
|
+
const dispatchAction = entry.dispatch ?? DEFAULT_DISPATCH;
|
|
28
|
+
const inputKey = entry.inputKey ?? manifest.inputKey ?? DEFAULT_INPUT_KEY;
|
|
29
|
+
const dispatchPath = (0, ufo.joinURL)(mountPath, dispatchAction);
|
|
30
|
+
const unsub = afs.subscribe({
|
|
31
|
+
type: eventType,
|
|
32
|
+
path: resolvedPath
|
|
33
|
+
}, (event) => {
|
|
34
|
+
const p = handleEvent(afs, dispatch, event.path, dispatchPath, inputKey);
|
|
35
|
+
pending.add(p);
|
|
36
|
+
p.finally(() => pending.delete(p));
|
|
37
|
+
});
|
|
38
|
+
unsubs.push(unsub);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
close: () => {
|
|
42
|
+
for (const u of unsubs) try {
|
|
43
|
+
u();
|
|
44
|
+
} catch {}
|
|
45
|
+
},
|
|
46
|
+
settled: async () => {
|
|
47
|
+
while (pending.size) await Promise.allSettled([...pending]);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function handleEvent(afs, dispatch, eventPath, dispatchPath, inputKey) {
|
|
52
|
+
try {
|
|
53
|
+
const payload = await readPayload(afs, eventPath);
|
|
54
|
+
await dispatch(dispatchPath, { [inputKey]: payload });
|
|
55
|
+
} catch (err) {
|
|
56
|
+
log.warn(`[agent-subscribe] dispatch failed for ${dispatchPath} (event ${eventPath}):`, err instanceof Error ? err.message : err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function readPayload(afs, path) {
|
|
60
|
+
if (!afs.read) return null;
|
|
61
|
+
const raw = (await afs.read(path))?.data?.content;
|
|
62
|
+
if (raw == null) return null;
|
|
63
|
+
const str = String(raw);
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(str);
|
|
66
|
+
} catch {
|
|
67
|
+
return str;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
exports.registerAgentSubscribes = registerAgentSubscribes;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AFSRoot, AgentManifest } from "@aigne/afs";
|
|
2
|
+
|
|
3
|
+
//#region src/program/agent-subscribe.d.ts
|
|
4
|
+
type AgentSubscribeDispatch = (path: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
5
|
+
interface RegisterAgentSubscribesOptions {
|
|
6
|
+
afs: AFSRoot;
|
|
7
|
+
manifest: AgentManifest;
|
|
8
|
+
mountPath: string;
|
|
9
|
+
dispatch?: AgentSubscribeDispatch;
|
|
10
|
+
}
|
|
11
|
+
interface AgentSubscribeHandle {
|
|
12
|
+
close(): void;
|
|
13
|
+
settled(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
declare function registerAgentSubscribes(opts: RegisterAgentSubscribesOptions): AgentSubscribeHandle;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AgentSubscribeDispatch, AgentSubscribeHandle, RegisterAgentSubscribesOptions, registerAgentSubscribes };
|
|
18
|
+
//# sourceMappingURL=agent-subscribe.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-subscribe.d.cts","names":[],"sources":["../../src/program/agent-subscribe.ts"],"mappings":";;;KAMY,sBAAA,IACV,IAAA,UACA,IAAA,EAAM,MAAA,sBACH,OAAA;AAAA,UAEY,8BAAA;EACf,GAAA,EAAK,OAAA;EACL,QAAA,EAAU,aAAA;EACV,SAAA;EACA,QAAA,GAAW,sBAAA;AAAA;AAAA,UAGI,oBAAA;EACf,KAAA;EACA,OAAA,IAAW,OAAA;AAAA;AAAA,iBAaG,uBAAA,CACd,IAAA,EAAM,8BAAA,GACL,oBAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AFSRoot, AgentManifest } from "@aigne/afs";
|
|
2
|
+
|
|
3
|
+
//#region src/program/agent-subscribe.d.ts
|
|
4
|
+
type AgentSubscribeDispatch = (path: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
5
|
+
interface RegisterAgentSubscribesOptions {
|
|
6
|
+
afs: AFSRoot;
|
|
7
|
+
manifest: AgentManifest;
|
|
8
|
+
mountPath: string;
|
|
9
|
+
dispatch?: AgentSubscribeDispatch;
|
|
10
|
+
}
|
|
11
|
+
interface AgentSubscribeHandle {
|
|
12
|
+
close(): void;
|
|
13
|
+
settled(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
declare function registerAgentSubscribes(opts: RegisterAgentSubscribesOptions): AgentSubscribeHandle;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AgentSubscribeDispatch, AgentSubscribeHandle, RegisterAgentSubscribesOptions, registerAgentSubscribes };
|
|
18
|
+
//# sourceMappingURL=agent-subscribe.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-subscribe.d.mts","names":[],"sources":["../../src/program/agent-subscribe.ts"],"mappings":";;;KAMY,sBAAA,IACV,IAAA,UACA,IAAA,EAAM,MAAA,sBACH,OAAA;AAAA,UAEY,8BAAA;EACf,GAAA,EAAK,OAAA;EACL,QAAA,EAAU,aAAA;EACV,SAAA;EACA,QAAA,GAAW,sBAAA;AAAA;AAAA,UAGI,oBAAA;EACf,KAAA;EACA,OAAA,IAAW,OAAA;AAAA;AAAA,iBAaG,uBAAA,CACd,IAAA,EAAM,8BAAA,GACL,oBAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { joinURL } from "ufo";
|
|
2
|
+
import { makeNsLog } from "@aigne/afs";
|
|
3
|
+
|
|
4
|
+
//#region src/program/agent-subscribe.ts
|
|
5
|
+
const log = makeNsLog("agent-runtime");
|
|
6
|
+
const SELF_TOKEN = "<self>";
|
|
7
|
+
const DEFAULT_EVENT = "afs:write";
|
|
8
|
+
const DEFAULT_DISPATCH = ".actions/run";
|
|
9
|
+
const DEFAULT_INPUT_KEY = "message";
|
|
10
|
+
const NOOP_HANDLE = {
|
|
11
|
+
close: () => {},
|
|
12
|
+
settled: () => Promise.resolve()
|
|
13
|
+
};
|
|
14
|
+
function registerAgentSubscribes(opts) {
|
|
15
|
+
const { afs, manifest, mountPath } = opts;
|
|
16
|
+
const subscribeList = manifest.subscribe ?? [];
|
|
17
|
+
if (subscribeList.length === 0) return NOOP_HANDLE;
|
|
18
|
+
if (!afs.subscribe) throw new Error("afs.subscribe not available for agent-subscribe registration");
|
|
19
|
+
if (!opts.dispatch && !afs.exec) throw new Error("afs.exec not available for subscribe dispatch");
|
|
20
|
+
const dispatch = opts.dispatch ?? ((path, args) => afs.exec(path, args, {}));
|
|
21
|
+
const blockletId = mountPath.split("/").filter(Boolean).at(-1) ?? "";
|
|
22
|
+
const pending = /* @__PURE__ */ new Set();
|
|
23
|
+
const unsubs = [];
|
|
24
|
+
for (const entry of subscribeList) {
|
|
25
|
+
const resolvedPath = entry.path.split(SELF_TOKEN).join(blockletId);
|
|
26
|
+
const eventType = entry.event ?? DEFAULT_EVENT;
|
|
27
|
+
const dispatchAction = entry.dispatch ?? DEFAULT_DISPATCH;
|
|
28
|
+
const inputKey = entry.inputKey ?? manifest.inputKey ?? DEFAULT_INPUT_KEY;
|
|
29
|
+
const dispatchPath = joinURL(mountPath, dispatchAction);
|
|
30
|
+
const unsub = afs.subscribe({
|
|
31
|
+
type: eventType,
|
|
32
|
+
path: resolvedPath
|
|
33
|
+
}, (event) => {
|
|
34
|
+
const p = handleEvent(afs, dispatch, event.path, dispatchPath, inputKey);
|
|
35
|
+
pending.add(p);
|
|
36
|
+
p.finally(() => pending.delete(p));
|
|
37
|
+
});
|
|
38
|
+
unsubs.push(unsub);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
close: () => {
|
|
42
|
+
for (const u of unsubs) try {
|
|
43
|
+
u();
|
|
44
|
+
} catch {}
|
|
45
|
+
},
|
|
46
|
+
settled: async () => {
|
|
47
|
+
while (pending.size) await Promise.allSettled([...pending]);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function handleEvent(afs, dispatch, eventPath, dispatchPath, inputKey) {
|
|
52
|
+
try {
|
|
53
|
+
const payload = await readPayload(afs, eventPath);
|
|
54
|
+
await dispatch(dispatchPath, { [inputKey]: payload });
|
|
55
|
+
} catch (err) {
|
|
56
|
+
log.warn(`[agent-subscribe] dispatch failed for ${dispatchPath} (event ${eventPath}):`, err instanceof Error ? err.message : err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function readPayload(afs, path) {
|
|
60
|
+
if (!afs.read) return null;
|
|
61
|
+
const raw = (await afs.read(path))?.data?.content;
|
|
62
|
+
if (raw == null) return null;
|
|
63
|
+
const str = String(raw);
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(str);
|
|
66
|
+
} catch {
|
|
67
|
+
return str;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { registerAgentSubscribes };
|
|
73
|
+
//# sourceMappingURL=agent-subscribe.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-subscribe.mjs","names":[],"sources":["../../src/program/agent-subscribe.ts"],"sourcesContent":["import type { AFSRoot, AgentManifest } from \"@aigne/afs\";\nimport { makeNsLog } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\n\nconst log = makeNsLog(\"agent-runtime\");\n\nexport type AgentSubscribeDispatch = (\n path: string,\n args: Record<string, unknown>,\n) => Promise<unknown>;\n\nexport interface RegisterAgentSubscribesOptions {\n afs: AFSRoot;\n manifest: AgentManifest;\n mountPath: string;\n dispatch?: AgentSubscribeDispatch;\n}\n\nexport interface AgentSubscribeHandle {\n close(): void;\n settled(): Promise<void>;\n}\n\nconst SELF_TOKEN = \"<self>\";\nconst DEFAULT_EVENT = \"afs:write\";\nconst DEFAULT_DISPATCH = \".actions/run\";\nconst DEFAULT_INPUT_KEY = \"message\";\n\nconst NOOP_HANDLE: AgentSubscribeHandle = {\n close: () => {},\n settled: () => Promise.resolve(),\n};\n\nexport function registerAgentSubscribes(\n opts: RegisterAgentSubscribesOptions,\n): AgentSubscribeHandle {\n const { afs, manifest, mountPath } = opts;\n const subscribeList = manifest.subscribe ?? [];\n if (subscribeList.length === 0) return NOOP_HANDLE;\n\n if (!afs.subscribe) {\n throw new Error(\"afs.subscribe not available for agent-subscribe registration\");\n }\n if (!opts.dispatch && !afs.exec) {\n throw new Error(\"afs.exec not available for subscribe dispatch\");\n }\n const dispatch: AgentSubscribeDispatch =\n opts.dispatch ?? ((path, args) => afs.exec!(path, args, {}));\n\n const blockletId = mountPath.split(\"/\").filter(Boolean).at(-1) ?? \"\";\n const pending = new Set<Promise<unknown>>();\n const unsubs: Array<() => void> = [];\n\n for (const entry of subscribeList) {\n const resolvedPath = entry.path.split(SELF_TOKEN).join(blockletId);\n const eventType = entry.event ?? DEFAULT_EVENT;\n const dispatchAction = entry.dispatch ?? DEFAULT_DISPATCH;\n const inputKey = entry.inputKey ?? manifest.inputKey ?? DEFAULT_INPUT_KEY;\n const dispatchPath = joinURL(mountPath, dispatchAction);\n\n const unsub = afs.subscribe({ type: eventType, path: resolvedPath }, (event) => {\n const p = handleEvent(afs, dispatch, event.path, dispatchPath, inputKey);\n pending.add(p);\n p.finally(() => pending.delete(p));\n });\n unsubs.push(unsub);\n }\n\n return {\n close: () => {\n for (const u of unsubs) {\n try {\n u();\n } catch {}\n }\n },\n settled: async () => {\n while (pending.size) {\n await Promise.allSettled([...pending]);\n }\n },\n };\n}\n\nasync function handleEvent(\n afs: AFSRoot,\n dispatch: AgentSubscribeDispatch,\n eventPath: string,\n dispatchPath: string,\n inputKey: string,\n): Promise<void> {\n try {\n const payload = await readPayload(afs, eventPath);\n await dispatch(dispatchPath, { [inputKey]: payload });\n } catch (err) {\n // A failing dispatch must not crash the EventBus or take down siblings.\n log.warn(\n `[agent-subscribe] dispatch failed for ${dispatchPath} (event ${eventPath}):`,\n err instanceof Error ? err.message : err,\n );\n }\n}\n\nasync function readPayload(afs: AFSRoot, path: string): Promise<unknown> {\n if (!afs.read) return null;\n const read = await afs.read(path);\n const raw = read?.data?.content;\n if (raw == null) return null;\n const str = String(raw);\n try {\n return JSON.parse(str);\n } catch {\n return str;\n }\n}\n"],"mappings":";;;;AAIA,MAAM,MAAM,UAAU,gBAAgB;AAmBtC,MAAM,aAAa;AACnB,MAAM,gBAAgB;AACtB,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAE1B,MAAM,cAAoC;CACxC,aAAa;CACb,eAAe,QAAQ,SAAS;CACjC;AAED,SAAgB,wBACd,MACsB;CACtB,MAAM,EAAE,KAAK,UAAU,cAAc;CACrC,MAAM,gBAAgB,SAAS,aAAa,EAAE;AAC9C,KAAI,cAAc,WAAW,EAAG,QAAO;AAEvC,KAAI,CAAC,IAAI,UACP,OAAM,IAAI,MAAM,+DAA+D;AAEjF,KAAI,CAAC,KAAK,YAAY,CAAC,IAAI,KACzB,OAAM,IAAI,MAAM,gDAAgD;CAElE,MAAM,WACJ,KAAK,cAAc,MAAM,SAAS,IAAI,KAAM,MAAM,MAAM,EAAE,CAAC;CAE7D,MAAM,aAAa,UAAU,MAAM,IAAI,CAAC,OAAO,QAAQ,CAAC,GAAG,GAAG,IAAI;CAClE,MAAM,0BAAU,IAAI,KAAuB;CAC3C,MAAM,SAA4B,EAAE;AAEpC,MAAK,MAAM,SAAS,eAAe;EACjC,MAAM,eAAe,MAAM,KAAK,MAAM,WAAW,CAAC,KAAK,WAAW;EAClE,MAAM,YAAY,MAAM,SAAS;EACjC,MAAM,iBAAiB,MAAM,YAAY;EACzC,MAAM,WAAW,MAAM,YAAY,SAAS,YAAY;EACxD,MAAM,eAAe,QAAQ,WAAW,eAAe;EAEvD,MAAM,QAAQ,IAAI,UAAU;GAAE,MAAM;GAAW,MAAM;GAAc,GAAG,UAAU;GAC9E,MAAM,IAAI,YAAY,KAAK,UAAU,MAAM,MAAM,cAAc,SAAS;AACxE,WAAQ,IAAI,EAAE;AACd,KAAE,cAAc,QAAQ,OAAO,EAAE,CAAC;IAClC;AACF,SAAO,KAAK,MAAM;;AAGpB,QAAO;EACL,aAAa;AACX,QAAK,MAAM,KAAK,OACd,KAAI;AACF,OAAG;WACG;;EAGZ,SAAS,YAAY;AACnB,UAAO,QAAQ,KACb,OAAM,QAAQ,WAAW,CAAC,GAAG,QAAQ,CAAC;;EAG3C;;AAGH,eAAe,YACb,KACA,UACA,WACA,cACA,UACe;AACf,KAAI;EACF,MAAM,UAAU,MAAM,YAAY,KAAK,UAAU;AACjD,QAAM,SAAS,cAAc,GAAG,WAAW,SAAS,CAAC;UAC9C,KAAK;AAEZ,MAAI,KACF,yCAAyC,aAAa,UAAU,UAAU,KAC1E,eAAe,QAAQ,IAAI,UAAU,IACtC;;;AAIL,eAAe,YAAY,KAAc,MAAgC;AACvE,KAAI,CAAC,IAAI,KAAM,QAAO;CAEtB,MAAM,OADO,MAAM,IAAI,KAAK,KAAK,GACf,MAAM;AACxB,KAAI,OAAO,KAAM,QAAO;CACxB,MAAM,MAAM,OAAO,IAAI;AACvB,KAAI;AACF,SAAO,KAAK,MAAM,IAAI;SAChB;AACN,SAAO"}
|