pi-subagents 0.80.0 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/bundle/agents.js +18 -0
- package/bundle/background-work.js +16 -0
- package/bundle/capability-ceiling.js +22 -0
- package/bundle/child-tool-plan.js +11 -0
- package/bundle/chunk-26C3WLYQ.js +8388 -0
- package/bundle/chunk-2XYWN7QJ.js +128 -0
- package/bundle/chunk-2ZSNH26H.js +4164 -0
- package/bundle/chunk-3DC5KBVP.js +235 -0
- package/bundle/chunk-3IF2PGW7.js +380 -0
- package/bundle/chunk-4QFZZV3O.js +57 -0
- package/bundle/chunk-563BHAZ5.js +1365 -0
- package/bundle/chunk-5LFLVSTM.js +260 -0
- package/bundle/chunk-62OCY2S4.js +14 -0
- package/bundle/chunk-74RT5YQE.js +326 -0
- package/bundle/chunk-7F6RKT6W.js +132 -0
- package/bundle/chunk-7J4ZXMY7.js +18 -0
- package/bundle/chunk-ARRKBB2B.js +179 -0
- package/bundle/chunk-BJN5LUQY.js +458 -0
- package/bundle/chunk-BPS2AGBZ.js +5421 -0
- package/bundle/chunk-CEKS3TFO.js +1337 -0
- package/bundle/chunk-CTPAE36Y.js +94 -0
- package/bundle/chunk-D4EHT5SJ.js +14 -0
- package/bundle/chunk-EYNJ6VL6.js +526 -0
- package/bundle/chunk-G5DKFLLI.js +1185 -0
- package/bundle/chunk-KSWQVGDW.js +1027 -0
- package/bundle/chunk-L5ZHE4L4.js +946 -0
- package/bundle/chunk-LSRUTHT7.js +57 -0
- package/bundle/chunk-N2BN7BF5.js +159 -0
- package/bundle/chunk-NF7IEKBH.js +490 -0
- package/bundle/chunk-NIXWDZZV.js +9 -0
- package/bundle/chunk-NNLASTQE.js +4082 -0
- package/bundle/chunk-TUWLXTAM.js +935 -0
- package/bundle/chunk-UKG4V45O.js +228 -0
- package/bundle/chunk-V2JWDB5U.js +753 -0
- package/bundle/chunk-V3BIUPLU.js +9163 -0
- package/bundle/chunk-V6MR5TOQ.js +270 -0
- package/bundle/chunk-VJHOELQP.js +8245 -0
- package/bundle/chunk-WSBNENFS.js +732 -0
- package/bundle/chunk-XMFLCKMQ.js +16664 -0
- package/bundle/chunk-YFCK7H2S.js +129 -0
- package/bundle/chunk-YYREO77V.js +137 -0
- package/bundle/chunk-Z7KVHQHL.js +173 -0
- package/bundle/chunk-ZBC44JJ3.js +8606 -0
- package/bundle/chunk-ZP3HODFH.js +175 -0
- package/bundle/control-channel.js +11 -0
- package/bundle/delegation.js +14 -0
- package/bundle/external-job-provider.js +20 -0
- package/bundle/external-runs.js +21 -0
- package/bundle/index.js +30 -0
- package/bundle/inspectors.js +8 -0
- package/bundle/intercom-bridge.js +11 -0
- package/bundle/preflight.js +425 -0
- package/bundle/project-panes.js +28 -0
- package/bundle/required-child-extensions.js +6 -0
- package/bundle/shared-types.js +8 -0
- package/bundle/workflow-resources.js +7 -0
- package/docs/extension-api.md +27 -0
- package/docs/observability.md +6 -2
- package/package.json +18 -18
- package/src/agents/frontmatter.d.ts +2 -0
- package/src/agents/frontmatter.js +9 -2
- package/src/api/delegation.d.ts +20 -0
- package/src/extension/index.js +27 -7
- package/src/runs/background/run-child-session.js +18 -0
- package/src/runs/background/stale-run-reconciler.js +2 -0
- package/src/runs/foreground/execution.js +39 -2
- package/src/runs/shared/structured-output.d.ts +1 -0
- package/src/runs/shared/structured-output.js +1 -0
- package/src/shared/accessible-dir.js +4 -1
- package/src/shared/provider-diagnostics.d.ts +9 -0
- package/src/shared/provider-diagnostics.js +75 -0
- package/src/shared/types.d.ts +3 -0
- package/src/slash/delegation-adapters.d.ts +3 -1
- package/src/slash/delegation-adapters.js +7 -0
- package/src/slash/prompt-template-bridge.js +3 -1
- package/src/slash/subagents-admin.d.ts +1 -0
- package/src/slash/subagents-admin.js +1 -1
- package/src/tui/fleet-layout.d.ts +20 -0
- package/src/tui/fleet-layout.js +17 -0
- package/src/tui/fleet-viewport.d.ts +12 -0
- package/src/tui/fleet-viewport.js +35 -0
- package/src/tui/fleet.d.ts +5 -6
- package/src/tui/fleet.js +69 -51
- package/src/workflows/structured-workflow-scripts.d.ts +1 -0
- package/src/workflows/structured-workflow-scripts.js +5 -4
- package/src/workflows/workflow-resources.js +2 -2
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAgentDir
|
|
3
|
+
} from "./chunk-ZBC44JJ3.js";
|
|
4
|
+
import {
|
|
5
|
+
TEMP_ARTIFACTS_DIR
|
|
6
|
+
} from "./chunk-5LFLVSTM.js";
|
|
7
|
+
|
|
8
|
+
// src/shared/artifacts.ts
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
var CLEANUP_MARKER_FILE = ".last-cleanup";
|
|
12
|
+
var PROJECT_SUBAGENTS_RELATIVE_DIR = ".pi/subagents";
|
|
13
|
+
var PROJECT_ARTIFACT_PATHS = [
|
|
14
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/output.md`,
|
|
15
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_input.md`,
|
|
16
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_output.md`,
|
|
17
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker.jsonl`,
|
|
18
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_transcript.jsonl`,
|
|
19
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_meta.json`,
|
|
20
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/progress/run/progress.md`,
|
|
21
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/outputs/output.md`,
|
|
22
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/outputs/run/output.md`,
|
|
23
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/chain-runs/run.json`
|
|
24
|
+
];
|
|
25
|
+
function globMatchesPath(pattern, filePath) {
|
|
26
|
+
let expression = "^";
|
|
27
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
28
|
+
const character = pattern[index];
|
|
29
|
+
if (character === void 0) break;
|
|
30
|
+
if (character === "*" && pattern[index + 1] === "*") {
|
|
31
|
+
index += 1;
|
|
32
|
+
if (pattern[index + 1] === "/") {
|
|
33
|
+
index += 1;
|
|
34
|
+
expression += "(?:.*/)?";
|
|
35
|
+
} else {
|
|
36
|
+
expression += ".*";
|
|
37
|
+
}
|
|
38
|
+
} else if (character === "*") {
|
|
39
|
+
expression += "[^/]*";
|
|
40
|
+
} else if (character === "?") {
|
|
41
|
+
expression += "[^/]";
|
|
42
|
+
} else if (character === "[") {
|
|
43
|
+
const end = pattern.indexOf("]", index + 1);
|
|
44
|
+
if (end === -1) expression += "\\[";
|
|
45
|
+
else {
|
|
46
|
+
expression += pattern.slice(index, end + 1);
|
|
47
|
+
index = end;
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
expression += character.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
return new RegExp(`${expression}$`).test(filePath);
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function normalizePattern(pattern) {
|
|
60
|
+
return pattern.replace(/^\.\//, "").replace(/^\//, "").replace(/\/+$/, "");
|
|
61
|
+
}
|
|
62
|
+
function patternMatchesArtifactPath(pattern, artifactPath) {
|
|
63
|
+
const normalized = normalizePattern(pattern);
|
|
64
|
+
return normalized === PROJECT_SUBAGENTS_RELATIVE_DIR || normalized === "*" || artifactPath.startsWith(`${normalized}/`) || globMatchesPath(normalized, artifactPath);
|
|
65
|
+
}
|
|
66
|
+
function ignoreFileExcludesProjectArtifacts(filePath) {
|
|
67
|
+
if (!fs.existsSync(filePath)) return false;
|
|
68
|
+
try {
|
|
69
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
70
|
+
for (const rawLine of fs.readFileSync(filePath, "utf-8").split(/\r?\n/)) {
|
|
71
|
+
const line = rawLine.trim();
|
|
72
|
+
if (!line || line.startsWith("#")) continue;
|
|
73
|
+
const negated = line.startsWith("!");
|
|
74
|
+
const pattern = negated ? line.slice(1) : line;
|
|
75
|
+
for (const artifactPath of PROJECT_ARTIFACT_PATHS) {
|
|
76
|
+
if (!patternMatchesArtifactPath(pattern, artifactPath)) continue;
|
|
77
|
+
if (negated) excluded.delete(artifactPath);
|
|
78
|
+
else excluded.add(artifactPath);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return excluded.size === PROJECT_ARTIFACT_PATHS.length;
|
|
82
|
+
} catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function filesIncludeProjectArtifacts(files) {
|
|
87
|
+
if (!Array.isArray(files)) return void 0;
|
|
88
|
+
const included = /* @__PURE__ */ new Set();
|
|
89
|
+
for (const entry of files) {
|
|
90
|
+
if (typeof entry !== "string") continue;
|
|
91
|
+
const negated = entry.startsWith("!");
|
|
92
|
+
const pattern = negated ? entry.slice(1) : entry;
|
|
93
|
+
for (const artifactPath of PROJECT_ARTIFACT_PATHS) {
|
|
94
|
+
if (!patternMatchesArtifactPath(pattern, artifactPath)) continue;
|
|
95
|
+
if (negated) included.delete(artifactPath);
|
|
96
|
+
else included.add(artifactPath);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return included.size > 0;
|
|
100
|
+
}
|
|
101
|
+
function getProjectArtifactPackagingWarning(cwd) {
|
|
102
|
+
const packagePath = path.join(cwd, "package.json");
|
|
103
|
+
if (!fs.existsSync(packagePath)) return void 0;
|
|
104
|
+
let packageJson;
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
107
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
108
|
+
packageJson = parsed;
|
|
109
|
+
} catch {
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
const filesIncludeArtifacts = filesIncludeProjectArtifacts(packageJson.files);
|
|
113
|
+
if (filesIncludeArtifacts === false) return void 0;
|
|
114
|
+
const npmIgnorePath = path.join(cwd, ".npmignore");
|
|
115
|
+
const ignorePath = fs.existsSync(npmIgnorePath) ? npmIgnorePath : path.join(cwd, ".gitignore");
|
|
116
|
+
if (filesIncludeArtifacts === void 0 && ignoreFileExcludesProjectArtifacts(ignorePath)) return void 0;
|
|
117
|
+
return "Project-scoped subagent artifacts can be included when this package is published. Add '.pi/subagents/' to .npmignore, restrict package.json files, or set artifactDir to 'session' or 'temp'.";
|
|
118
|
+
}
|
|
119
|
+
function getProjectSubagentsDir(cwd) {
|
|
120
|
+
return path.join(cwd, PROJECT_SUBAGENTS_RELATIVE_DIR);
|
|
121
|
+
}
|
|
122
|
+
function getProjectArtifactsDir(cwd) {
|
|
123
|
+
return path.join(getProjectSubagentsDir(cwd), "artifacts");
|
|
124
|
+
}
|
|
125
|
+
function getArtifactsDir(sessionFile, projectCwd, dirPreference = "session") {
|
|
126
|
+
switch (dirPreference) {
|
|
127
|
+
case "session":
|
|
128
|
+
if (sessionFile) {
|
|
129
|
+
const sessionDir = path.dirname(sessionFile);
|
|
130
|
+
return path.join(sessionDir, "subagent-artifacts");
|
|
131
|
+
}
|
|
132
|
+
return TEMP_ARTIFACTS_DIR;
|
|
133
|
+
case "temp":
|
|
134
|
+
return TEMP_ARTIFACTS_DIR;
|
|
135
|
+
case "project":
|
|
136
|
+
if (projectCwd) return getProjectArtifactsDir(projectCwd);
|
|
137
|
+
if (sessionFile) {
|
|
138
|
+
const sessionDir = path.dirname(sessionFile);
|
|
139
|
+
return path.join(sessionDir, "subagent-artifacts");
|
|
140
|
+
}
|
|
141
|
+
return TEMP_ARTIFACTS_DIR;
|
|
142
|
+
default:
|
|
143
|
+
throw new Error(`Unsupported artifactDir ${JSON.stringify(dirPreference)}; expected "project", "session", or "temp".`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function getArtifactPaths(artifactsDir, runId, agent, index) {
|
|
147
|
+
const suffix = index !== void 0 ? `_${index}` : "";
|
|
148
|
+
const safeAgent = agent.replace(/[^\w.-]/g, "_");
|
|
149
|
+
const base = `${runId}_${safeAgent}${suffix}`;
|
|
150
|
+
return {
|
|
151
|
+
inputPath: path.join(artifactsDir, `${base}_input.md`),
|
|
152
|
+
outputPath: path.join(artifactsDir, `${base}_output.md`),
|
|
153
|
+
jsonlPath: path.join(artifactsDir, `${base}.jsonl`),
|
|
154
|
+
transcriptPath: path.join(artifactsDir, `${base}_transcript.jsonl`),
|
|
155
|
+
metadataPath: path.join(artifactsDir, `${base}_meta.json`)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function ensureArtifactsDir(dir) {
|
|
159
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
160
|
+
}
|
|
161
|
+
function writeArtifact(filePath, content) {
|
|
162
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
163
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
164
|
+
}
|
|
165
|
+
function formatOutputArtifactContent(input) {
|
|
166
|
+
if (input.output.trim() || !input.error) return input.output;
|
|
167
|
+
const lines = ["Subagent run failed before producing output.", "", "Error:", input.error];
|
|
168
|
+
if (input.transcriptPath) lines.push("", `Transcript: ${input.transcriptPath}`);
|
|
169
|
+
if (input.metadataPath) lines.push(`Metadata: ${input.metadataPath}`);
|
|
170
|
+
return lines.join("\n");
|
|
171
|
+
}
|
|
172
|
+
function writeMetadata(filePath, metadata) {
|
|
173
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
174
|
+
fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
175
|
+
}
|
|
176
|
+
function appendJsonl(filePath, line) {
|
|
177
|
+
fs.appendFileSync(filePath, `${line}
|
|
178
|
+
`);
|
|
179
|
+
}
|
|
180
|
+
function cleanupOldArtifacts(dir, maxAgeDays) {
|
|
181
|
+
if (maxAgeDays <= 0 || !fs.existsSync(dir)) return;
|
|
182
|
+
const markerPath = path.join(dir, CLEANUP_MARKER_FILE);
|
|
183
|
+
const now = Date.now();
|
|
184
|
+
if (fs.existsSync(markerPath)) {
|
|
185
|
+
const stat = fs.statSync(markerPath);
|
|
186
|
+
if (now - stat.mtimeMs < 24 * 60 * 60 * 1e3) return;
|
|
187
|
+
}
|
|
188
|
+
const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
189
|
+
const cutoff = now - maxAgeMs;
|
|
190
|
+
for (const file of fs.readdirSync(dir)) {
|
|
191
|
+
if (file === CLEANUP_MARKER_FILE) continue;
|
|
192
|
+
const filePath = path.join(dir, file);
|
|
193
|
+
try {
|
|
194
|
+
const stat = fs.statSync(filePath);
|
|
195
|
+
if (stat.mtimeMs < cutoff) {
|
|
196
|
+
fs.unlinkSync(filePath);
|
|
197
|
+
}
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
fs.writeFileSync(markerPath, String(now));
|
|
202
|
+
}
|
|
203
|
+
function cleanupAllArtifactDirs(maxAgeDays) {
|
|
204
|
+
cleanupOldArtifacts(TEMP_ARTIFACTS_DIR, maxAgeDays);
|
|
205
|
+
const sessionsBase = path.join(getAgentDir(), "sessions");
|
|
206
|
+
if (!fs.existsSync(sessionsBase)) return;
|
|
207
|
+
let dirs;
|
|
208
|
+
try {
|
|
209
|
+
dirs = fs.readdirSync(sessionsBase);
|
|
210
|
+
} catch {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
for (const dir of dirs) {
|
|
214
|
+
const artifactsDir = path.join(sessionsBase, dir, "subagent-artifacts");
|
|
215
|
+
try {
|
|
216
|
+
cleanupOldArtifacts(artifactsDir, maxAgeDays);
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export {
|
|
223
|
+
PROJECT_SUBAGENTS_RELATIVE_DIR,
|
|
224
|
+
getProjectArtifactPackagingWarning,
|
|
225
|
+
getProjectSubagentsDir,
|
|
226
|
+
getArtifactsDir,
|
|
227
|
+
getArtifactPaths,
|
|
228
|
+
ensureArtifactsDir,
|
|
229
|
+
writeArtifact,
|
|
230
|
+
formatOutputArtifactContent,
|
|
231
|
+
writeMetadata,
|
|
232
|
+
appendJsonl,
|
|
233
|
+
cleanupOldArtifacts,
|
|
234
|
+
cleanupAllArtifactDirs
|
|
235
|
+
};
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BUILTIN_AGENT_NAMES,
|
|
3
|
+
CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL,
|
|
4
|
+
applyRuntimeAgentSettings,
|
|
5
|
+
isCodeOwnedExternalCliAdapterId,
|
|
6
|
+
parseExternalCliCapabilityNarrowing,
|
|
7
|
+
validateAcceptanceInput,
|
|
8
|
+
validateCodeOwnedProfileRunner,
|
|
9
|
+
validatePermissionRules,
|
|
10
|
+
validateToolBudgetConfig
|
|
11
|
+
} from "./chunk-ZBC44JJ3.js";
|
|
12
|
+
|
|
13
|
+
// src/agents/runtime-agent-registry.ts
|
|
14
|
+
var RUNTIME_AGENT_REGISTRY_KEY = "pi-subagents.runtime-agents.v1";
|
|
15
|
+
var MAX_RUNTIME_AGENTS_PER_PI = 200;
|
|
16
|
+
var MAX_AGENT_NAME_LENGTH = 128;
|
|
17
|
+
var MAX_DESCRIPTION_LENGTH = 4096;
|
|
18
|
+
var MAX_SYSTEM_PROMPT_LENGTH = 1024 * 1024;
|
|
19
|
+
var MAX_FIELD_STRING_LENGTH = 8192;
|
|
20
|
+
function defaultSystemPromptMode(name) {
|
|
21
|
+
return name === "delegate" ? "append" : "replace";
|
|
22
|
+
}
|
|
23
|
+
function defaultInheritProjectContext(name) {
|
|
24
|
+
return name === "delegate";
|
|
25
|
+
}
|
|
26
|
+
function defaultInheritSkills() {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
function registry() {
|
|
30
|
+
const key = Symbol.for(RUNTIME_AGENT_REGISTRY_KEY);
|
|
31
|
+
const globalObject = globalThis;
|
|
32
|
+
const existing = globalObject[key];
|
|
33
|
+
if (existing === void 0) {
|
|
34
|
+
const created = { version: 1, byPi: /* @__PURE__ */ new WeakMap() };
|
|
35
|
+
globalObject[key] = created;
|
|
36
|
+
return created;
|
|
37
|
+
}
|
|
38
|
+
if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
|
|
39
|
+
throw new Error(`Malformed runtime agent registry at Symbol.for("${RUNTIME_AGENT_REGISTRY_KEY}").`);
|
|
40
|
+
}
|
|
41
|
+
const candidate = existing;
|
|
42
|
+
if (candidate.version !== 1 || !(candidate.byPi instanceof WeakMap)) {
|
|
43
|
+
throw new Error(`Unsupported runtime agent registry at Symbol.for("${RUNTIME_AGENT_REGISTRY_KEY}").`);
|
|
44
|
+
}
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
function validatePi(value) {
|
|
48
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Runtime agent pi must be an ExtensionAPI object.");
|
|
49
|
+
const pi = value;
|
|
50
|
+
if (typeof pi.on !== "function" || typeof pi.registerTool !== "function") throw new Error("Runtime agent pi must be an ExtensionAPI object.");
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function validateString(value, field, maxLength) {
|
|
54
|
+
if (typeof value !== "string" || value.length === 0 || value.trim() !== value) {
|
|
55
|
+
throw new Error(`${field} must be a non-empty string without leading or trailing whitespace.`);
|
|
56
|
+
}
|
|
57
|
+
if (value.length > maxLength) throw new Error(`${field} must be at most ${maxLength} characters.`);
|
|
58
|
+
if (value.includes("\0")) throw new Error(`${field} must not contain NUL characters.`);
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
function validateOptionalString(value, field, maxLength = MAX_FIELD_STRING_LENGTH) {
|
|
62
|
+
if (value === void 0) return void 0;
|
|
63
|
+
return validateString(value, field, maxLength);
|
|
64
|
+
}
|
|
65
|
+
function validateStringList(value, field) {
|
|
66
|
+
if (value === void 0) return void 0;
|
|
67
|
+
if (!Array.isArray(value)) throw new Error(`${field} must be an array of strings when provided.`);
|
|
68
|
+
return [...new Set(value.map((entry, index) => validateString(entry, `${field}[${index}]`, MAX_FIELD_STRING_LENGTH)))];
|
|
69
|
+
}
|
|
70
|
+
function validatePositiveInteger(value, field) {
|
|
71
|
+
if (value === void 0) return void 0;
|
|
72
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) throw new Error(`${field} must be a positive integer when provided.`);
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
function validateBoolean(value, field) {
|
|
76
|
+
if (value === void 0) return void 0;
|
|
77
|
+
if (typeof value !== "boolean") throw new Error(`${field} must be a boolean when provided.`);
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
function isJsonSerializable(value) {
|
|
81
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
82
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
83
|
+
if (Array.isArray(value)) return value.every(isJsonSerializable);
|
|
84
|
+
if (value && typeof value === "object") return Object.values(value).every(isJsonSerializable);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function validateRunner(value) {
|
|
88
|
+
if (value === void 0) return void 0;
|
|
89
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Runtime agent definition runner must be an object when provided.");
|
|
90
|
+
const runner = value;
|
|
91
|
+
if (runner.type === "pi") {
|
|
92
|
+
if (Object.keys(runner).some((key) => key !== "type")) throw new Error("Runtime agent definition Pi runner supports only 'type'.");
|
|
93
|
+
return { type: "pi" };
|
|
94
|
+
}
|
|
95
|
+
if (runner.type === "external-job") {
|
|
96
|
+
if (typeof runner.provider !== "string" || !runner.provider.trim() || runner.provider.trim() !== runner.provider) throw new Error("Runtime agent definition external-job runner requires a non-empty trimmed provider string.");
|
|
97
|
+
if (runner.options !== void 0 && (!runner.options || typeof runner.options !== "object" || Array.isArray(runner.options) || !isJsonSerializable(runner.options))) throw new Error("Runtime agent definition external-job runner options must be a JSON-serializable object.");
|
|
98
|
+
const supported2 = /* @__PURE__ */ new Set(["type", "provider", "options"]);
|
|
99
|
+
const unknown2 = Object.keys(runner).filter((key) => !supported2.has(key));
|
|
100
|
+
if (unknown2.length > 0) throw new Error(`Runtime agent definition external-job runner has unsupported fields: ${unknown2.join(", ")}.`);
|
|
101
|
+
return { type: "external-job", provider: runner.provider, ...runner.options ? { options: runner.options } : {} };
|
|
102
|
+
}
|
|
103
|
+
if (runner.type !== "external-cli") throw new Error("Runtime agent definition runner.type must be 'pi', 'external-cli', or 'external-job'.");
|
|
104
|
+
if (typeof runner.command !== "string" || !runner.command.trim()) throw new Error("Runtime agent definition external-cli runner requires a non-empty command string.");
|
|
105
|
+
if (runner.args !== void 0 && (!Array.isArray(runner.args) || runner.args.some((arg) => typeof arg !== "string"))) throw new Error("Runtime agent definition external-cli runner args must be an array of strings.");
|
|
106
|
+
if (runner.adapter !== void 0 && !isCodeOwnedExternalCliAdapterId(runner.adapter)) throw new Error(`Runtime agent definition external-cli runner adapter must be ${CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL}.`);
|
|
107
|
+
if (runner.adapter !== void 0 && Array.isArray(runner.args) && runner.args.length > 0) throw new Error(`Runtime agent definition ${runner.adapter} adapter owns its argv; runner args are not supported.`);
|
|
108
|
+
if (runner.promptDelivery !== void 0 && runner.promptDelivery !== "stdin") throw new Error("Runtime agent definition external-cli runner promptDelivery must be 'stdin'.");
|
|
109
|
+
const capabilities = parseExternalCliCapabilityNarrowing(runner.capabilities, "Runtime agent definition external-cli runner capabilities");
|
|
110
|
+
const supported = /* @__PURE__ */ new Set(["type", "adapter", "command", "args", "promptDelivery", "capabilities"]);
|
|
111
|
+
const unknown = Object.keys(runner).filter((key) => !supported.has(key));
|
|
112
|
+
if (unknown.length > 0) throw new Error(`Runtime agent definition external-cli runner has unsupported fields: ${unknown.join(", ")}.`);
|
|
113
|
+
const args = runner.args;
|
|
114
|
+
return { type: "external-cli", ...isCodeOwnedExternalCliAdapterId(runner.adapter) ? { adapter: runner.adapter } : {}, command: runner.command.trim(), ...args?.length ? { args } : {}, ...runner.promptDelivery ? { promptDelivery: "stdin" } : {}, ...capabilities ? { capabilities } : {} };
|
|
115
|
+
}
|
|
116
|
+
function validateAcceptance(value) {
|
|
117
|
+
const errors = validateAcceptanceInput(value, "Runtime agent definition defaultAcceptance");
|
|
118
|
+
if (errors.length > 0) throw new Error(errors.join(" "));
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
function validateToolBudget(value) {
|
|
122
|
+
const result = validateToolBudgetConfig(value, "Runtime agent definition toolBudget");
|
|
123
|
+
if (result.error) throw new Error(result.error);
|
|
124
|
+
return result.budget;
|
|
125
|
+
}
|
|
126
|
+
function validateDefinition(value) {
|
|
127
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Runtime agent definition must be an object.");
|
|
128
|
+
const definition = value;
|
|
129
|
+
const supported = /* @__PURE__ */ new Set([
|
|
130
|
+
"description",
|
|
131
|
+
"systemPrompt",
|
|
132
|
+
"aliases",
|
|
133
|
+
"tools",
|
|
134
|
+
"excludeTools",
|
|
135
|
+
"allowNestedSubagents",
|
|
136
|
+
"mcpDirectTools",
|
|
137
|
+
"model",
|
|
138
|
+
"thinking",
|
|
139
|
+
"systemPromptMode",
|
|
140
|
+
"inheritProjectContext",
|
|
141
|
+
"inheritGlobalContext",
|
|
142
|
+
"inheritSkills",
|
|
143
|
+
"defaultContext",
|
|
144
|
+
"defaultAsync",
|
|
145
|
+
"defaultTimeoutMs",
|
|
146
|
+
"defaultToolTimeoutMs",
|
|
147
|
+
"defaultAcceptance",
|
|
148
|
+
"acceptanceRole",
|
|
149
|
+
"runner",
|
|
150
|
+
"machine",
|
|
151
|
+
"skills",
|
|
152
|
+
"skillPath",
|
|
153
|
+
"extensions",
|
|
154
|
+
"subagentOnlyExtensions",
|
|
155
|
+
"mutationTools",
|
|
156
|
+
"output",
|
|
157
|
+
"outputMode",
|
|
158
|
+
"defaultReads",
|
|
159
|
+
"defaultProgress",
|
|
160
|
+
"interactive",
|
|
161
|
+
"maxSubagentDepth",
|
|
162
|
+
"toolBudget",
|
|
163
|
+
"permissions"
|
|
164
|
+
]);
|
|
165
|
+
const unknown = Object.keys(definition).filter((key) => !supported.has(key));
|
|
166
|
+
if (unknown.length > 0) throw new Error(`Runtime agent definition has unknown fields: ${unknown.join(", ")}.`);
|
|
167
|
+
const systemPromptMode = definition.systemPromptMode;
|
|
168
|
+
if (systemPromptMode !== void 0 && systemPromptMode !== "append" && systemPromptMode !== "replace") throw new Error("Runtime agent definition systemPromptMode must be 'append' or 'replace'.");
|
|
169
|
+
const defaultContext = definition.defaultContext;
|
|
170
|
+
if (defaultContext !== void 0 && defaultContext !== "fresh" && defaultContext !== "fork") throw new Error("Runtime agent definition defaultContext must be 'fresh' or 'fork'.");
|
|
171
|
+
const thinking = definition.thinking;
|
|
172
|
+
if (thinking !== void 0 && thinking !== false && typeof thinking !== "string") throw new Error("Runtime agent definition thinking must be a string or false when provided.");
|
|
173
|
+
const acceptanceRole = definition.acceptanceRole;
|
|
174
|
+
if (acceptanceRole !== void 0 && acceptanceRole !== "read-only" && acceptanceRole !== "writer") throw new Error("Runtime agent definition acceptanceRole must be 'read-only' or 'writer'.");
|
|
175
|
+
const outputMode = definition.outputMode;
|
|
176
|
+
if (outputMode !== void 0 && outputMode !== "inline" && outputMode !== "file-only") throw new Error("Runtime agent definition outputMode must be 'inline' or 'file-only'.");
|
|
177
|
+
const aliases = validateStringList(definition.aliases, "Runtime agent definition aliases");
|
|
178
|
+
const tools = validateStringList(definition.tools, "Runtime agent definition tools");
|
|
179
|
+
const excludeTools = validateStringList(definition.excludeTools, "Runtime agent definition excludeTools");
|
|
180
|
+
const allowNestedSubagents = validateBoolean(definition.allowNestedSubagents, "Runtime agent definition allowNestedSubagents");
|
|
181
|
+
const mcpDirectTools = validateStringList(definition.mcpDirectTools, "Runtime agent definition mcpDirectTools");
|
|
182
|
+
const model = validateOptionalString(definition.model, "Runtime agent definition model");
|
|
183
|
+
if (definition.fallbackModels !== void 0) throw new Error("Runtime agent definition fallbackModels was removed; configure one model instead.");
|
|
184
|
+
const inheritProjectContext = validateBoolean(definition.inheritProjectContext, "Runtime agent definition inheritProjectContext");
|
|
185
|
+
const inheritGlobalContext = validateBoolean(definition.inheritGlobalContext, "Runtime agent definition inheritGlobalContext");
|
|
186
|
+
const inheritSkills = validateBoolean(definition.inheritSkills, "Runtime agent definition inheritSkills");
|
|
187
|
+
const defaultAsync = validateBoolean(definition.defaultAsync, "Runtime agent definition defaultAsync");
|
|
188
|
+
const defaultTimeoutMs = validatePositiveInteger(definition.defaultTimeoutMs, "Runtime agent definition defaultTimeoutMs");
|
|
189
|
+
const defaultToolTimeoutMs = validatePositiveInteger(definition.defaultToolTimeoutMs, "Runtime agent definition defaultToolTimeoutMs");
|
|
190
|
+
const defaultAcceptance = validateAcceptance(definition.defaultAcceptance);
|
|
191
|
+
const runner = validateRunner(definition.runner);
|
|
192
|
+
const skills = validateStringList(definition.skills, "Runtime agent definition skills");
|
|
193
|
+
const skillPath = validateStringList(definition.skillPath, "Runtime agent definition skillPath");
|
|
194
|
+
const extensions = validateStringList(definition.extensions, "Runtime agent definition extensions");
|
|
195
|
+
const subagentOnlyExtensions = validateStringList(definition.subagentOnlyExtensions, "Runtime agent definition subagentOnlyExtensions");
|
|
196
|
+
const mutationTools = validateStringList(definition.mutationTools, "Runtime agent definition mutationTools");
|
|
197
|
+
const machine = validateOptionalString(definition.machine, "Runtime agent definition machine");
|
|
198
|
+
const output = validateOptionalString(definition.output, "Runtime agent definition output");
|
|
199
|
+
const defaultReads = validateStringList(definition.defaultReads, "Runtime agent definition defaultReads");
|
|
200
|
+
const defaultProgress = validateBoolean(definition.defaultProgress, "Runtime agent definition defaultProgress");
|
|
201
|
+
const interactive = validateBoolean(definition.interactive, "Runtime agent definition interactive");
|
|
202
|
+
const maxSubagentDepth = validatePositiveInteger(definition.maxSubagentDepth, "Runtime agent definition maxSubagentDepth");
|
|
203
|
+
const toolBudget = validateToolBudget(definition.toolBudget);
|
|
204
|
+
const permissions = validatePermissionRules(definition.permissions, "Runtime agent definition permissions");
|
|
205
|
+
return {
|
|
206
|
+
description: validateString(definition.description, "Runtime agent definition description", MAX_DESCRIPTION_LENGTH),
|
|
207
|
+
systemPrompt: validateString(definition.systemPrompt, "Runtime agent definition systemPrompt", MAX_SYSTEM_PROMPT_LENGTH),
|
|
208
|
+
...aliases ? { aliases } : {},
|
|
209
|
+
...tools ? { tools } : {},
|
|
210
|
+
...excludeTools ? { excludeTools } : {},
|
|
211
|
+
...allowNestedSubagents !== void 0 ? { allowNestedSubagents } : {},
|
|
212
|
+
...mcpDirectTools ? { mcpDirectTools } : {},
|
|
213
|
+
...model ? { model } : {},
|
|
214
|
+
...thinking !== void 0 ? { thinking } : {},
|
|
215
|
+
...systemPromptMode !== void 0 ? { systemPromptMode } : {},
|
|
216
|
+
...inheritProjectContext !== void 0 ? { inheritProjectContext } : {},
|
|
217
|
+
...inheritGlobalContext !== void 0 ? { inheritGlobalContext } : {},
|
|
218
|
+
...inheritSkills !== void 0 ? { inheritSkills } : {},
|
|
219
|
+
...defaultContext !== void 0 ? { defaultContext } : {},
|
|
220
|
+
...defaultAsync !== void 0 ? { defaultAsync } : {},
|
|
221
|
+
...defaultTimeoutMs !== void 0 ? { defaultTimeoutMs } : {},
|
|
222
|
+
...defaultToolTimeoutMs !== void 0 ? { defaultToolTimeoutMs } : {},
|
|
223
|
+
...defaultAcceptance !== void 0 ? { defaultAcceptance } : {},
|
|
224
|
+
...acceptanceRole !== void 0 ? { acceptanceRole } : {},
|
|
225
|
+
...runner !== void 0 ? { runner } : {},
|
|
226
|
+
...skills ? { skills } : {},
|
|
227
|
+
...skillPath ? { skillPath } : {},
|
|
228
|
+
...extensions ? { extensions } : {},
|
|
229
|
+
...subagentOnlyExtensions ? { subagentOnlyExtensions } : {},
|
|
230
|
+
...mutationTools ? { mutationTools } : {},
|
|
231
|
+
...machine ? { machine } : {},
|
|
232
|
+
...output ? { output } : {},
|
|
233
|
+
...outputMode !== void 0 ? { outputMode } : {},
|
|
234
|
+
...defaultReads ? { defaultReads } : {},
|
|
235
|
+
...defaultProgress !== void 0 ? { defaultProgress } : {},
|
|
236
|
+
...interactive !== void 0 ? { interactive } : {},
|
|
237
|
+
...maxSubagentDepth !== void 0 ? { maxSubagentDepth } : {},
|
|
238
|
+
...toolBudget !== void 0 ? { toolBudget } : {},
|
|
239
|
+
...permissions !== void 0 ? { permissions } : {}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function normalizeAliases(rawAliases, agentName) {
|
|
243
|
+
const aliases = [...new Set((rawAliases ?? []).map((alias) => alias.trim()).filter(Boolean))].filter((alias) => alias !== agentName);
|
|
244
|
+
return aliases.length > 0 ? aliases : void 0;
|
|
245
|
+
}
|
|
246
|
+
function identityKeys(agent) {
|
|
247
|
+
return [agent.name, ...agent.localName ? [agent.localName] : [], ...agent.aliases ?? []];
|
|
248
|
+
}
|
|
249
|
+
function assertNoIdentityCollisions(agents, context) {
|
|
250
|
+
const seen = /* @__PURE__ */ new Map();
|
|
251
|
+
for (const agent of agents) {
|
|
252
|
+
for (const key of identityKeys(agent)) {
|
|
253
|
+
const previous = seen.get(key);
|
|
254
|
+
if (previous !== void 0) throw new Error(`${context} collision for '${key}' between '${previous}' and '${agent.name}'.`);
|
|
255
|
+
seen.set(key, agent.name);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function assertNoRuntimeCollision(agent, existing) {
|
|
260
|
+
const existingKeys = /* @__PURE__ */ new Map();
|
|
261
|
+
for (const registered of existing) {
|
|
262
|
+
for (const key of identityKeys(registered)) existingKeys.set(key, registered.name);
|
|
263
|
+
}
|
|
264
|
+
for (const key of identityKeys(agent)) {
|
|
265
|
+
const previous = existingKeys.get(key);
|
|
266
|
+
if (previous !== void 0) throw new Error(`Runtime agent '${agent.name}' collides with runtime agent '${previous}' on name or alias '${key}'.`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function assertNoBuiltinCollision(agent) {
|
|
270
|
+
for (const key of identityKeys(agent)) {
|
|
271
|
+
if (BUILTIN_AGENT_NAMES.includes(key)) throw new Error(`Runtime agent '${agent.name}' collides with builtin agent '${key}'.`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function toAgentConfig(name, definition) {
|
|
275
|
+
const aliases = normalizeAliases(definition.aliases, name);
|
|
276
|
+
const agent = {
|
|
277
|
+
name,
|
|
278
|
+
description: definition.description,
|
|
279
|
+
...aliases ? { aliases } : {},
|
|
280
|
+
...definition.runner !== void 0 ? { runner: definition.runner } : {},
|
|
281
|
+
...definition.tools !== void 0 ? { tools: [...definition.tools] } : {},
|
|
282
|
+
...definition.excludeTools !== void 0 ? { excludeTools: [...definition.excludeTools] } : {},
|
|
283
|
+
...definition.allowNestedSubagents !== void 0 ? { allowNestedSubagents: definition.allowNestedSubagents } : {},
|
|
284
|
+
...definition.mcpDirectTools !== void 0 ? { mcpDirectTools: [...definition.mcpDirectTools] } : {},
|
|
285
|
+
...definition.model !== void 0 ? { model: definition.model } : {},
|
|
286
|
+
...definition.thinking !== void 0 ? { thinking: definition.thinking } : {},
|
|
287
|
+
systemPromptMode: definition.systemPromptMode ?? defaultSystemPromptMode(name),
|
|
288
|
+
inheritProjectContext: definition.inheritProjectContext ?? defaultInheritProjectContext(name),
|
|
289
|
+
inheritGlobalContext: definition.inheritGlobalContext ?? false,
|
|
290
|
+
inheritSkills: definition.inheritSkills ?? defaultInheritSkills(),
|
|
291
|
+
...definition.defaultContext !== void 0 ? { defaultContext: definition.defaultContext } : {},
|
|
292
|
+
...definition.defaultAsync !== void 0 ? { defaultAsync: definition.defaultAsync } : {},
|
|
293
|
+
...definition.defaultTimeoutMs !== void 0 ? { defaultTimeoutMs: definition.defaultTimeoutMs } : {},
|
|
294
|
+
...definition.defaultToolTimeoutMs !== void 0 ? { defaultToolTimeoutMs: definition.defaultToolTimeoutMs } : {},
|
|
295
|
+
...definition.defaultAcceptance !== void 0 ? { defaultAcceptance: definition.defaultAcceptance } : {},
|
|
296
|
+
...definition.acceptanceRole !== void 0 ? { acceptanceRole: definition.acceptanceRole } : {},
|
|
297
|
+
systemPrompt: definition.systemPrompt,
|
|
298
|
+
source: "runtime",
|
|
299
|
+
filePath: `runtime:${name}`,
|
|
300
|
+
...definition.skills !== void 0 ? { skills: [...definition.skills] } : {},
|
|
301
|
+
...definition.skillPath !== void 0 ? { skillPath: [...definition.skillPath] } : {},
|
|
302
|
+
...definition.extensions !== void 0 ? { extensions: [...definition.extensions] } : {},
|
|
303
|
+
...definition.subagentOnlyExtensions !== void 0 ? { subagentOnlyExtensions: [...definition.subagentOnlyExtensions] } : {},
|
|
304
|
+
...definition.mutationTools !== void 0 ? { mutationTools: [...definition.mutationTools] } : {},
|
|
305
|
+
...definition.machine !== void 0 ? { machine: definition.machine } : {},
|
|
306
|
+
...definition.output !== void 0 ? { output: definition.output } : {},
|
|
307
|
+
...definition.outputMode !== void 0 ? { outputMode: definition.outputMode } : {},
|
|
308
|
+
...definition.defaultReads !== void 0 ? { defaultReads: [...definition.defaultReads] } : {},
|
|
309
|
+
...definition.defaultProgress !== void 0 ? { defaultProgress: definition.defaultProgress } : {},
|
|
310
|
+
...definition.interactive !== void 0 ? { interactive: definition.interactive } : {},
|
|
311
|
+
...definition.maxSubagentDepth !== void 0 ? { maxSubagentDepth: definition.maxSubagentDepth } : {},
|
|
312
|
+
...definition.toolBudget !== void 0 ? { toolBudget: definition.toolBudget } : {},
|
|
313
|
+
...definition.permissions !== void 0 ? { permissions: definition.permissions } : {}
|
|
314
|
+
};
|
|
315
|
+
assertNoIdentityCollisions([agent], `Runtime agent '${name}'`);
|
|
316
|
+
return agent;
|
|
317
|
+
}
|
|
318
|
+
function registerRuntimeAgent(input) {
|
|
319
|
+
const pi = validatePi(input.pi);
|
|
320
|
+
const name = validateString(input.name, "Runtime agent name", MAX_AGENT_NAME_LENGTH);
|
|
321
|
+
const definition = validateDefinition(input.definition);
|
|
322
|
+
const agent = toAgentConfig(name, definition);
|
|
323
|
+
const profileError = validateCodeOwnedProfileRunner(agent);
|
|
324
|
+
if (profileError) throw new Error(profileError);
|
|
325
|
+
assertNoBuiltinCollision(agent);
|
|
326
|
+
const current = registry();
|
|
327
|
+
const records = current.byPi.get(pi) ?? [];
|
|
328
|
+
if (records.length >= MAX_RUNTIME_AGENTS_PER_PI) throw new Error(`Runtime agent registry supports at most ${MAX_RUNTIME_AGENTS_PER_PI} agents per Pi runtime.`);
|
|
329
|
+
assertNoRuntimeCollision(agent, records.map((record2) => record2.agent));
|
|
330
|
+
const record = { pi, agent };
|
|
331
|
+
records.push(record);
|
|
332
|
+
current.byPi.set(pi, records);
|
|
333
|
+
let disposed = false;
|
|
334
|
+
return {
|
|
335
|
+
dispose() {
|
|
336
|
+
if (disposed) return;
|
|
337
|
+
disposed = true;
|
|
338
|
+
const latest = current.byPi.get(pi);
|
|
339
|
+
if (!latest) return;
|
|
340
|
+
const next = latest.filter((entry) => entry !== record);
|
|
341
|
+
if (next.length > 0) current.byPi.set(pi, next);
|
|
342
|
+
else current.byPi.delete(pi);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function clearRuntimeAgentsForPi(pi) {
|
|
347
|
+
registry().byPi.delete(pi);
|
|
348
|
+
}
|
|
349
|
+
function listRuntimeAgentConfigs(pi) {
|
|
350
|
+
return (registry().byPi.get(pi) ?? []).map((record) => ({ ...record.agent, aliases: record.agent.aliases ? [...record.agent.aliases] : void 0 }));
|
|
351
|
+
}
|
|
352
|
+
function assertNoConfiguredCollision(configuredAgents, runtimeAgents) {
|
|
353
|
+
const configured = /* @__PURE__ */ new Map();
|
|
354
|
+
for (const agent of configuredAgents) {
|
|
355
|
+
for (const key of identityKeys(agent)) configured.set(key, agent.name);
|
|
356
|
+
}
|
|
357
|
+
for (const agent of runtimeAgents) {
|
|
358
|
+
for (const key of identityKeys(agent)) {
|
|
359
|
+
const previous = configured.get(key);
|
|
360
|
+
if (previous !== void 0) {
|
|
361
|
+
throw new Error(`Runtime agent '${agent.name}' collides with configured agent '${previous}' on name or alias '${key}'.`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function mergeRuntimeAgents(pi, discovered, configuredAgents = discovered.agents, settings) {
|
|
367
|
+
const registered = listRuntimeAgentConfigs(pi).filter((agent) => agent.disabled !== true);
|
|
368
|
+
if (registered.length === 0) return discovered;
|
|
369
|
+
assertNoIdentityCollisions(registered, "Runtime agent registration");
|
|
370
|
+
assertNoConfiguredCollision(configuredAgents, registered);
|
|
371
|
+
const runtimeAgents = settings ? applyRuntimeAgentSettings(registered, settings) : registered;
|
|
372
|
+
return { ...discovered, agents: [...discovered.agents, ...runtimeAgents] };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export {
|
|
376
|
+
registerRuntimeAgent,
|
|
377
|
+
clearRuntimeAgentsForPi,
|
|
378
|
+
listRuntimeAgentConfigs,
|
|
379
|
+
mergeRuntimeAgents
|
|
380
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// src/runs/shared/herdr-pi-protocol.ts
|
|
2
|
+
var HERDR_PI_PROTOCOL = 1;
|
|
3
|
+
var HERDR_PI_MAX_FRAME_BYTES = 1024 * 1024;
|
|
4
|
+
var HERDR_PI_MODE_ENV = "PI_SUBAGENTS_HERDR_BRIDGE";
|
|
5
|
+
var HERDR_PI_RUN_ENV = "PI_SUBAGENTS_HERDR_RUN_ID";
|
|
6
|
+
var HERDR_PI_RUNTIME_DIR_ENV = "PI_SUBAGENTS_HERDR_RUNTIME_DIR";
|
|
7
|
+
var SAFE_ID = /^[A-Za-z0-9_-]{8,96}$/u;
|
|
8
|
+
function validateHerdrPiRunId(value) {
|
|
9
|
+
if (typeof value !== "string" || !SAFE_ID.test(value)) throw new Error("Herdr Pi bridge run identity is invalid.");
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function encodeHerdrPiFrame(frame) {
|
|
13
|
+
const data = Buffer.from(`${JSON.stringify(frame)}
|
|
14
|
+
`, "utf8");
|
|
15
|
+
if (data.byteLength > HERDR_PI_MAX_FRAME_BYTES) throw new Error(`Herdr Pi frame exceeds ${HERDR_PI_MAX_FRAME_BYTES} bytes.`);
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
var HerdrPiFrameDecoder = class {
|
|
19
|
+
#buffer = Buffer.alloc(0);
|
|
20
|
+
push(chunk) {
|
|
21
|
+
this.#buffer = Buffer.concat([this.#buffer, chunk]);
|
|
22
|
+
if (this.#buffer.byteLength > HERDR_PI_MAX_FRAME_BYTES) throw new Error(`Herdr Pi frame exceeds ${HERDR_PI_MAX_FRAME_BYTES} bytes.`);
|
|
23
|
+
const frames = [];
|
|
24
|
+
for (; ; ) {
|
|
25
|
+
const newline = this.#buffer.indexOf(10);
|
|
26
|
+
if (newline < 0) break;
|
|
27
|
+
const line = this.#buffer.subarray(0, newline);
|
|
28
|
+
this.#buffer = this.#buffer.subarray(newline + 1);
|
|
29
|
+
let value;
|
|
30
|
+
try {
|
|
31
|
+
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(line));
|
|
32
|
+
} catch {
|
|
33
|
+
throw new Error("Herdr Pi bridge emitted malformed JSON or UTF-8.");
|
|
34
|
+
}
|
|
35
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Herdr Pi bridge frame must be an object.");
|
|
36
|
+
const frame = value;
|
|
37
|
+
if (frame.protocol !== HERDR_PI_PROTOCOL || typeof frame.type !== "string") throw new Error("Herdr Pi bridge protocol mismatch.");
|
|
38
|
+
validateHerdrPiRunId(frame.runId);
|
|
39
|
+
frames.push(frame);
|
|
40
|
+
}
|
|
41
|
+
return frames;
|
|
42
|
+
}
|
|
43
|
+
end() {
|
|
44
|
+
if (this.#buffer.byteLength) throw new Error("Herdr Pi bridge ended with a partial frame.");
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
HERDR_PI_PROTOCOL,
|
|
50
|
+
HERDR_PI_MAX_FRAME_BYTES,
|
|
51
|
+
HERDR_PI_MODE_ENV,
|
|
52
|
+
HERDR_PI_RUN_ENV,
|
|
53
|
+
HERDR_PI_RUNTIME_DIR_ENV,
|
|
54
|
+
validateHerdrPiRunId,
|
|
55
|
+
encodeHerdrPiFrame,
|
|
56
|
+
HerdrPiFrameDecoder
|
|
57
|
+
};
|