@amaster.ai/employee-runtime-connector 0.1.0-beta.52 → 0.1.0-beta.54
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/dist/amaster-runtime-daemon.mjs +330 -84
- package/dist/amaster-runtime.mjs +1 -1
- package/package.json +1 -1
|
@@ -1789,8 +1789,82 @@ function syncAmasterProviderFiles(agentDir, executorEnv) {
|
|
|
1789
1789
|
};
|
|
1790
1790
|
}
|
|
1791
1791
|
|
|
1792
|
+
// src/amaster-runtime-daemon/pi-mcp-args-normalizer.mjs
|
|
1793
|
+
function isJsonObject(value) {
|
|
1794
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1795
|
+
}
|
|
1796
|
+
function escapeLiteralJsonStringControlCharacters(value) {
|
|
1797
|
+
let output = "";
|
|
1798
|
+
let inString = false;
|
|
1799
|
+
let escaped = false;
|
|
1800
|
+
let changed = false;
|
|
1801
|
+
for (const character of value) {
|
|
1802
|
+
if (!inString) {
|
|
1803
|
+
output += character;
|
|
1804
|
+
if (character === '"') inString = true;
|
|
1805
|
+
continue;
|
|
1806
|
+
}
|
|
1807
|
+
if (escaped) {
|
|
1808
|
+
output += character;
|
|
1809
|
+
escaped = false;
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1812
|
+
if (character === "\\") {
|
|
1813
|
+
output += character;
|
|
1814
|
+
escaped = true;
|
|
1815
|
+
continue;
|
|
1816
|
+
}
|
|
1817
|
+
if (character === '"') {
|
|
1818
|
+
output += character;
|
|
1819
|
+
inString = false;
|
|
1820
|
+
continue;
|
|
1821
|
+
}
|
|
1822
|
+
const escapedControlCharacter = character === "\n" ? "\\n" : character === "\r" ? "\\r" : character === " " ? "\\t" : character === "\b" ? "\\b" : character === "\f" ? "\\f" : character.charCodeAt(0) < 32 ? `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}` : null;
|
|
1823
|
+
if (escapedControlCharacter) {
|
|
1824
|
+
output += escapedControlCharacter;
|
|
1825
|
+
changed = true;
|
|
1826
|
+
} else {
|
|
1827
|
+
output += character;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
return changed ? output : value;
|
|
1831
|
+
}
|
|
1832
|
+
function normalizePiMcpProxyArgs(value) {
|
|
1833
|
+
if (typeof value !== "string") return { value, repaired: false };
|
|
1834
|
+
try {
|
|
1835
|
+
JSON.parse(value);
|
|
1836
|
+
return { value, repaired: false };
|
|
1837
|
+
} catch {
|
|
1838
|
+
const repairedValue = escapeLiteralJsonStringControlCharacters(value);
|
|
1839
|
+
if (repairedValue === value) return { value, repaired: false };
|
|
1840
|
+
try {
|
|
1841
|
+
return isJsonObject(JSON.parse(repairedValue)) ? { value: repairedValue, repaired: true } : { value, repaired: false };
|
|
1842
|
+
} catch {
|
|
1843
|
+
return { value, repaired: false };
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
function registerManagedPiMcpArgsNormalizer(pi) {
|
|
1848
|
+
pi.on("tool_call", (event) => {
|
|
1849
|
+
if (event?.toolName !== "mcp" || !event.input || typeof event.input !== "object") return;
|
|
1850
|
+
const normalized = normalizePiMcpProxyArgs(event.input.args);
|
|
1851
|
+
if (normalized.repaired) event.input.args = normalized.value;
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
function managedPiMcpArgsNormalizerExtensionSource() {
|
|
1855
|
+
return [
|
|
1856
|
+
isJsonObject.toString(),
|
|
1857
|
+
escapeLiteralJsonStringControlCharacters.toString(),
|
|
1858
|
+
normalizePiMcpProxyArgs.toString(),
|
|
1859
|
+
`export default ${registerManagedPiMcpArgsNormalizer.toString()};`,
|
|
1860
|
+
""
|
|
1861
|
+
].join("\n\n");
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1792
1864
|
// src/amaster-runtime-daemon/pi-managed-mcp-profile.mjs
|
|
1793
1865
|
var MANAGED_PI_MCP_TOOL_MODE = "proxy_only";
|
|
1866
|
+
var MANAGED_PI_MCP_ARGS_NORMALIZATION = "json_string_control_characters_v1";
|
|
1867
|
+
var MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME = "amaster-mcp-args-normalizer.mjs";
|
|
1794
1868
|
function createManagedPiMcpProfileApi(options = {}) {
|
|
1795
1869
|
const spawnSyncImpl = typeof options.spawnSync === "function" ? options.spawnSync : spawnSync2;
|
|
1796
1870
|
const nowImpl = typeof options.now === "function" ? options.now : Date.now;
|
|
@@ -2162,6 +2236,12 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2162
2236
|
if (typeof sourceConfig.channel === "string" && ["stable", "beta", "dev", "canary"].includes(sourceConfig.channel)) {
|
|
2163
2237
|
config.channel = sourceConfig.channel;
|
|
2164
2238
|
}
|
|
2239
|
+
if (typeof sourceConfig.sessionMode === "string" && ["persistent", "isolated", "existing"].includes(sourceConfig.sessionMode)) {
|
|
2240
|
+
config.sessionMode = sourceConfig.sessionMode;
|
|
2241
|
+
}
|
|
2242
|
+
if (typeof sourceConfig.userDataDir === "string" && sourceConfig.userDataDir.trim().length > 0) {
|
|
2243
|
+
config.userDataDir = sourceConfig.userDataDir.trim();
|
|
2244
|
+
}
|
|
2165
2245
|
return {
|
|
2166
2246
|
packageSpec,
|
|
2167
2247
|
plugin: {
|
|
@@ -2241,6 +2321,12 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2241
2321
|
};
|
|
2242
2322
|
writePrivateFile2(join4(agentDir, "settings.json"), `${JSON.stringify(settings, null, 2)}
|
|
2243
2323
|
`);
|
|
2324
|
+
const extensionsDir = join4(agentDir, "extensions");
|
|
2325
|
+
mkdirSync3(extensionsDir, { recursive: true, mode: 448 });
|
|
2326
|
+
writePrivateFile2(
|
|
2327
|
+
join4(extensionsDir, MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME),
|
|
2328
|
+
managedPiMcpArgsNormalizerExtensionSource()
|
|
2329
|
+
);
|
|
2244
2330
|
copyPrivateFile(join4(source, "models.json"), join4(agentDir, "models.json"));
|
|
2245
2331
|
const authSource = join4(source, "auth.json");
|
|
2246
2332
|
const protectedValues = [];
|
|
@@ -2389,6 +2475,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2389
2475
|
...executorAttestation,
|
|
2390
2476
|
mcpAdapterVersion: seededRuntime.adapterVersion,
|
|
2391
2477
|
mcpToolMode: MANAGED_PI_MCP_TOOL_MODE,
|
|
2478
|
+
mcpArgsNormalization: MANAGED_PI_MCP_ARGS_NORMALIZATION,
|
|
2392
2479
|
configMode: "isolated_home_run_scoped_mcp_file",
|
|
2393
2480
|
namespace: SUPPORTED_SERVER_NAME2,
|
|
2394
2481
|
schemaVersion: SUPPORTED_SCHEMA_VERSION2,
|
|
@@ -2904,10 +2991,14 @@ function removeRunCompletionState(directory, commandId) {
|
|
|
2904
2991
|
}
|
|
2905
2992
|
|
|
2906
2993
|
// src/amaster-runtime-daemon/prompt-compiler.mjs
|
|
2907
|
-
var
|
|
2908
|
-
var DEADLINE_POSTURE_GUARD = "Named-window:skip_this_window_and_continue; no lower-quality/approval-bypass/fabrication/whole-task-stop; deadline_posture_receipt=targetMilestoneRef,posture,onMiss,taskContinuation,next owner/action; not Server proof";
|
|
2994
|
+
var DEADLINE_POSTURE_GUARD = "If a named time window or milestone is missed, skip that window and keep the task moving: never lower quality, bypass approvals, fabricate results, or stop the whole task because of the miss. Record a deadline-posture receipt with targetMilestoneRef, posture, onMiss=skip_this_window_and_continue, taskContinuation, and the next owner/action; the receipt is an execution signal, not Server-side proof.";
|
|
2909
2995
|
var MIN_PROMPT_BUDGET_CHARS = 8192;
|
|
2910
|
-
var
|
|
2996
|
+
var MAX_RESOLVED_DEPENDENCY_REQUIRED_READS = 20;
|
|
2997
|
+
function promptBudgetError(code, message) {
|
|
2998
|
+
const error = new Error(message);
|
|
2999
|
+
error.code = code;
|
|
3000
|
+
return error;
|
|
3001
|
+
}
|
|
2911
3002
|
var CONTINUATION_WAKE_PATTERN = /(continuation|continued|retry|approved|liveness|resume|max_turn)/i;
|
|
2912
3003
|
var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
|
|
2913
3004
|
"finish_successful_run_handoff",
|
|
@@ -2916,15 +3007,6 @@ var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
|
|
|
2916
3007
|
function isRecoveryWakeReason(wakeReason) {
|
|
2917
3008
|
return RECOVERY_WAKE_REASONS.has(wakeReason);
|
|
2918
3009
|
}
|
|
2919
|
-
function stringifyBoundedJson(value, maxChars = 24e3) {
|
|
2920
|
-
let text = "";
|
|
2921
|
-
try {
|
|
2922
|
-
text = JSON.stringify(value, null, 2);
|
|
2923
|
-
} catch {
|
|
2924
|
-
text = String(value);
|
|
2925
|
-
}
|
|
2926
|
-
return truncateText(text, maxChars);
|
|
2927
|
-
}
|
|
2928
3010
|
function jsonText(value) {
|
|
2929
3011
|
return JSON.stringify(value, null, 2);
|
|
2930
3012
|
}
|
|
@@ -2938,7 +3020,7 @@ function jsonCharLength(value) {
|
|
|
2938
3020
|
function estimatedTokens(chars) {
|
|
2939
3021
|
return Math.ceil(chars / 4);
|
|
2940
3022
|
}
|
|
2941
|
-
function
|
|
3023
|
+
function promptContextMode(input) {
|
|
2942
3024
|
const nativeSession = asRecord(input.nativeSession);
|
|
2943
3025
|
if (nativeSession.mode === "governed_action_approval" || readString(input.context?.resumeFromRunId) || isRecoveryWakeReason(input.wakeReason) || CONTINUATION_WAKE_PATTERN.test(input.wakeReason ?? "")) return "continuation";
|
|
2944
3026
|
if (nativeSession.resume === true || Object.keys(asRecord(input.context?.paperclipContinuationSummary)).length > 0) {
|
|
@@ -2946,6 +3028,22 @@ function contextMode(input) {
|
|
|
2946
3028
|
}
|
|
2947
3029
|
return "cold";
|
|
2948
3030
|
}
|
|
3031
|
+
function filterDuplicatedTaskComments(context, mode) {
|
|
3032
|
+
if (mode !== "cold") return context;
|
|
3033
|
+
const record5 = asRecord(context);
|
|
3034
|
+
const included = new Set(
|
|
3035
|
+
(Array.isArray(record5.paperclipTaskMarkdownCommentIds) ? record5.paperclipTaskMarkdownCommentIds : []).map((entry) => readString(entry)).filter(Boolean)
|
|
3036
|
+
);
|
|
3037
|
+
if (included.size === 0) return context;
|
|
3038
|
+
const wake = asRecord(record5.paperclipWake);
|
|
3039
|
+
const comments = Array.isArray(wake.comments) ? wake.comments : [];
|
|
3040
|
+
const kept = comments.filter((entry) => {
|
|
3041
|
+
const id = readString(asRecord(entry).id);
|
|
3042
|
+
return !id || !included.has(id);
|
|
3043
|
+
});
|
|
3044
|
+
if (kept.length === comments.length) return context;
|
|
3045
|
+
return { ...record5, paperclipWake: { ...wake, comments: kept } };
|
|
3046
|
+
}
|
|
2949
3047
|
function commentRefs(context) {
|
|
2950
3048
|
const comments = Array.isArray(asRecord(context.paperclipWake).comments) ? asRecord(context.paperclipWake).comments : [];
|
|
2951
3049
|
return comments.map((entry) => readString(asRecord(entry).id)).filter(Boolean);
|
|
@@ -3041,6 +3139,7 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3041
3139
|
}
|
|
3042
3140
|
const summaries = contextCopy ?? wakeCopy ?? [];
|
|
3043
3141
|
const tuples = [];
|
|
3142
|
+
const overflowRefs = [];
|
|
3044
3143
|
const seenTuples = /* @__PURE__ */ new Set();
|
|
3045
3144
|
const detailLines = [];
|
|
3046
3145
|
const detailSourceRefs = [];
|
|
@@ -3091,15 +3190,19 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3091
3190
|
]);
|
|
3092
3191
|
if (seenTuples.has(tupleKey)) continue;
|
|
3093
3192
|
seenTuples.add(tupleKey);
|
|
3094
|
-
tuples.
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3193
|
+
if (tuples.length >= MAX_RESOLVED_DEPENDENCY_REQUIRED_READS) {
|
|
3194
|
+
overflowRefs.push({ selector: blockerSelector, key });
|
|
3195
|
+
} else {
|
|
3196
|
+
tuples.push({
|
|
3197
|
+
blockerId,
|
|
3198
|
+
blockerSelector,
|
|
3199
|
+
documentId,
|
|
3200
|
+
key,
|
|
3201
|
+
expectedLatestRevisionId,
|
|
3202
|
+
expectedLatestRevisionNumber: latestRevisionNumber ?? null,
|
|
3203
|
+
observedAt: readString(document.updatedAt) ?? blockerObservedAt
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3103
3206
|
const documentTitle = readString(document.title);
|
|
3104
3207
|
detailLines.push(
|
|
3105
3208
|
` Document: ${key}${documentTitle ? ` (${documentTitle})` : ""}${latestRevisionNumber != null ? ` revision ${latestRevisionNumber}` : ""}`
|
|
@@ -3118,6 +3221,11 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3118
3221
|
if (workProductSummary) detailLines.push(` ${workProductSummary}`);
|
|
3119
3222
|
}
|
|
3120
3223
|
}
|
|
3224
|
+
if (overflowRefs.length > 0) {
|
|
3225
|
+
detailLines.push(
|
|
3226
|
+
` \u2026mandatory required reads are capped at ${MAX_RESOLVED_DEPENDENCY_REQUIRED_READS}; the remaining ${overflowRefs.length} predecessor document(s) are listed under On-demand Context References.`
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3121
3229
|
const requiredLines = tuples.length > 0 ? [
|
|
3122
3230
|
"Accepted predecessor outputs are binding inputs unless this issue explicitly requests reconsideration.",
|
|
3123
3231
|
"Before any downstream document/artifact write, review request, status mutation, or completion, perform every Required read.",
|
|
@@ -3153,7 +3261,8 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3153
3261
|
observedAt: detailObservedAt,
|
|
3154
3262
|
freshness: detailSourceRefs.map(() => snapshotFreshness),
|
|
3155
3263
|
scope: detailSourceRefs.map(() => contextScope)
|
|
3156
|
-
}
|
|
3264
|
+
},
|
|
3265
|
+
overflowRefs
|
|
3157
3266
|
};
|
|
3158
3267
|
}
|
|
3159
3268
|
function verifiedCompanyContextSection(context) {
|
|
@@ -3173,7 +3282,7 @@ function verifiedCompanyContextSection(context) {
|
|
|
3173
3282
|
content: [
|
|
3174
3283
|
"Use these server-snapshotted current Company facts as authoritative context for this run.",
|
|
3175
3284
|
"The current verification contract does not supply shareholder structure or a financial baseline; treat them as unknown unless separate evidence is present, and do not describe the verified registration facts below as missing.",
|
|
3176
|
-
|
|
3285
|
+
jsonText(companyContext)
|
|
3177
3286
|
].join("\n"),
|
|
3178
3287
|
sourceRef: [
|
|
3179
3288
|
`company:${companyId}`,
|
|
@@ -3185,12 +3294,29 @@ function verifiedCompanyContextSection(context) {
|
|
|
3185
3294
|
].filter(Boolean)
|
|
3186
3295
|
};
|
|
3187
3296
|
}
|
|
3297
|
+
function wikiAccessRuleLine(input) {
|
|
3298
|
+
const access = asRecord(input.wikiAccess);
|
|
3299
|
+
const tools = input.hasGovernedMcp === true && access.tools === true;
|
|
3300
|
+
const treePath = readString(access.treePath);
|
|
3301
|
+
if (tools && treePath) {
|
|
3302
|
+
return `- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages via the amaster MCP, and the wiki tree at ${treePath} (read wiki/index.md there first).`;
|
|
3303
|
+
}
|
|
3304
|
+
if (tools) {
|
|
3305
|
+
return "- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages via the amaster MCP. Use them for targeted lookup before re-deriving knowledge the company already holds.";
|
|
3306
|
+
}
|
|
3307
|
+
if (treePath) {
|
|
3308
|
+
return `- Company wiki access in this run: the wiki tree at ${treePath}. Read wiki/index.md first (every page listed with a one-line summary), then open the specific pages you need; wiki_* tools are not available in this run.`;
|
|
3309
|
+
}
|
|
3310
|
+
return "";
|
|
3311
|
+
}
|
|
3188
3312
|
function fixedRules(input, includeIssueLine) {
|
|
3189
3313
|
return [
|
|
3190
3314
|
"## AMaster Runtime Connector Task",
|
|
3191
3315
|
"MirrorX task.",
|
|
3192
3316
|
"Use only the declared workspace; make concrete progress and report concisely.",
|
|
3193
|
-
"Before changing the task status to done, audit every explicit requirement in the task against the final evidence. A successful tool or document write proves delivery, not acceptance: inspect the delivered content for required sections, diagrams, tables, and factual constraints.
|
|
3317
|
+
"Before changing the task status to done, audit every explicit requirement in the task against the final evidence. A successful tool or document write proves delivery, not acceptance: inspect the delivered content for required sections, diagrams, tables, and factual constraints.",
|
|
3318
|
+
"Do not leave stale in-progress wording such as \u201Ccurrent run\u201D in a terminal deliverable; rewrite it to the final observed state. Do not list finalization itself as remaining or next work in a terminal deliverable.",
|
|
3319
|
+
"If any requirement is missing or cannot be verified, do not mark done. To request review, use create_interaction with kind request_confirmation and payload.resolutionMode review; never call update_parent with status in_review. Otherwise keep the issue todo or blocked with the exact gap and next owner.",
|
|
3194
3320
|
DEADLINE_POSTURE_GUARD,
|
|
3195
3321
|
"Do not install operating-system or user-global packages, and do not use host package managers such as brew, apt, yum, or global pip/npm installs. Use tools already available or workspace-local dependencies or virtual environments. If a required renderer or evaluator is unavailable, keep the source artifact, record the exact verification gap, and do not mutate the host.",
|
|
3196
3322
|
`- command id: ${input.commandId}`,
|
|
@@ -3203,9 +3329,10 @@ function fixedRules(input, includeIssueLine) {
|
|
|
3203
3329
|
input.managed ? "Use the execution workspace as cwd. Never recursively scan the source workspace, the user's home directory, or any path outside the execution workspace. Only inspect a specific external source path when the task explicitly requires that exact path." : "",
|
|
3204
3330
|
input.wakeReason ? `- wake reason: ${input.wakeReason}` : "",
|
|
3205
3331
|
input.hasGovernedMcp ? "- AMaster mutations are available only through the managed amaster MCP server. Use discovered tools and immediate typed results; never call AMaster mutation REST endpoints directly." : "- No mutation channel is available for this command. Keep the run read-only and report the missing Runtime V2 capability as a blocker.",
|
|
3332
|
+
wikiAccessRuleLine(input),
|
|
3206
3333
|
"- Runtime Artifact lineage fields sourceWorkProductId and sourceWorkProductIds accept only current artifact work product ids returned as result.effectResult.workProductId by a succeeded upload_artifact action. Never pass a documentId or revisionId as artifact lineage.",
|
|
3207
3334
|
"- When all inputs are issue documents and there is no source artifact work product, persist the derived result with upsert_document and do not call upload_artifact for a derived or review artifact.",
|
|
3208
|
-
input.hasGovernedMcp && input.executorKind === "pi" && input.managedMcpToolMode === "proxy_only" ? "- For proxy-only Pi MCP writes, put the complete target argument object directly in
|
|
3335
|
+
input.hasGovernedMcp && input.executorKind === "pi" && input.managedMcpToolMode === "proxy_only" ? "- For proxy-only Pi MCP writes, put the complete target argument object directly in actual `mcp` string `args` as strict JSON; escape quotes, backslashes, and control characters. Do not stage or print tool calls. If inner JSON syntax fails, correct it once without changing values; never repeat a possibly accepted call. After `runtime_action.describe`, emit the write." : ""
|
|
3209
3336
|
].filter(Boolean).join("\n");
|
|
3210
3337
|
}
|
|
3211
3338
|
function approvalContinuationText(input) {
|
|
@@ -3230,7 +3357,7 @@ function interactionResolutionText(context) {
|
|
|
3230
3357
|
"Treat this resolved interaction as the authoritative delta for this run.",
|
|
3231
3358
|
readString(resolution.status) === "changes_requested" ? "Apply every requested change before creating a replacement review." : "",
|
|
3232
3359
|
exactDocumentRevisionDirective,
|
|
3233
|
-
|
|
3360
|
+
jsonText(resolution)
|
|
3234
3361
|
].filter(Boolean).join("\n");
|
|
3235
3362
|
}
|
|
3236
3363
|
function recoveryInstructionText(input) {
|
|
@@ -3365,6 +3492,25 @@ function runtimeDecompositionRequirementText(context) {
|
|
|
3365
3492
|
`Requirement source: ${sourceType}:${sourceId}@${sourceRevision}`
|
|
3366
3493
|
].join("\n");
|
|
3367
3494
|
}
|
|
3495
|
+
function readIssueEvidenceCommentCallText(issueId, commentId, options) {
|
|
3496
|
+
const readArguments = { refs: [{ kind: "issue_comment", issueId, commentId }] };
|
|
3497
|
+
if (options?.executorKind === "pi" && options?.managedMcpToolMode === "proxy_only") {
|
|
3498
|
+
return `emit an mcp proxy call: ${JSON.stringify({ server: "amaster", tool: "amaster.read_issue_evidence", args: JSON.stringify(readArguments) })}`;
|
|
3499
|
+
}
|
|
3500
|
+
return `call amaster.read_issue_evidence with these exact arguments: ${JSON.stringify(readArguments)}`;
|
|
3501
|
+
}
|
|
3502
|
+
function overflowDependencyRefsText(overflowRefs) {
|
|
3503
|
+
if (!Array.isArray(overflowRefs) || overflowRefs.length === 0) return "";
|
|
3504
|
+
return [
|
|
3505
|
+
"Additional predecessor documents available on demand \u2014 fetch each with amaster.read_issue_document before relying on it:",
|
|
3506
|
+
...overflowRefs.map((ref) => `- issue ${JSON.stringify(ref.selector)}, key ${JSON.stringify(ref.key)}`)
|
|
3507
|
+
].join("\n");
|
|
3508
|
+
}
|
|
3509
|
+
function taskCommentRefGuidance(input) {
|
|
3510
|
+
if (!input.hasGovernedMcp || !readString(input.issueId)) return "";
|
|
3511
|
+
const call = readIssueEvidenceCommentCallText(input.issueId, "<id>", input);
|
|
3512
|
+
return `References like comment:<id> above mark truncated comment bodies. Fetch the full text before relying on them \u2014 ${call} (replace <id> with the referenced comment id).`;
|
|
3513
|
+
}
|
|
3368
3514
|
function piMcpProxyExamplesText(input) {
|
|
3369
3515
|
if (!input.hasGovernedMcp || input.executorKind !== "pi" || input.managedMcpToolMode !== "proxy_only" || isRecoveryWakeReason(input.wakeReason)) return "";
|
|
3370
3516
|
const proxy = (tool, args) => JSON.stringify({
|
|
@@ -3375,10 +3521,11 @@ function piMcpProxyExamplesText(input) {
|
|
|
3375
3521
|
return [
|
|
3376
3522
|
"The Pi native tool is the outer `mcp` proxy. Emit these as actual tool calls; `args` is the stringified inner canonical object:",
|
|
3377
3523
|
"Keep review payload strings short. Reference the exact document key and revision in `target`; do not duplicate the reviewed document body in `prompt` or `detailsMarkdown`.",
|
|
3524
|
+
"update_parent.comment creates a separate persistent issue comment. Omit it when add_comment already recorded the message.",
|
|
3378
3525
|
`- describe: ${proxy("runtime_action.describe", { schemaVersion: "runtime-action-v1", actionType: "update_parent" })}`,
|
|
3379
|
-
`- submit: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-progress", action: { type: "update_parent", status: "in_progress"
|
|
3526
|
+
`- submit: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-progress", action: { type: "update_parent", status: "in_progress" } })}`,
|
|
3380
3527
|
`- submit review interaction: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-review", action: { type: "create_interaction", kind: "request_confirmation", continuationPolicy: "wake_assignee_on_accept", payload: { version: 1, resolutionMode: "review", prompt: "Review `plan` revision 1.", target: { type: "issue_document", issueId: "11111111-1111-4111-8111-111111111111", documentId: "33333333-3333-4333-8333-333333333333", key: "plan", revisionId: "22222222-2222-4222-8222-222222222222", revisionNumber: 1 } } } })}`,
|
|
3381
|
-
`- plan: ${proxy("runtime_action.plan", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-plan", actions: [{ type: "update_parent", status: "in_progress"
|
|
3528
|
+
`- plan: ${proxy("runtime_action.plan", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-plan", actions: [{ type: "update_parent", status: "in_progress" }] })}`,
|
|
3382
3529
|
`- commit the returned plan revision: ${proxy("runtime_action.commit", { schemaVersion: "runtime-action-v1", planId: "11111111-1111-4111-8111-111111111111", revision: "plan-revision-1" })}`,
|
|
3383
3530
|
`- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`
|
|
3384
3531
|
].join("\n");
|
|
@@ -3437,19 +3584,19 @@ function buildManifest(mode, maxChars, sections, governedReadProvenance, usedCha
|
|
|
3437
3584
|
budget: {
|
|
3438
3585
|
totalChars: maxChars,
|
|
3439
3586
|
usedChars,
|
|
3440
|
-
utilization: (usedChars / maxChars).toFixed(4)
|
|
3587
|
+
utilization: maxChars === null ? null : (usedChars / maxChars).toFixed(4)
|
|
3441
3588
|
},
|
|
3442
3589
|
sections: sections.map(manifestEntry),
|
|
3443
3590
|
governedReadProvenance
|
|
3444
3591
|
};
|
|
3445
3592
|
}
|
|
3446
3593
|
function compileCommandPromptWithManifest(input, options = {}) {
|
|
3447
|
-
const maxChars = Number(options.maxChars
|
|
3448
|
-
if (!Number.isInteger(maxChars) || maxChars < MIN_PROMPT_BUDGET_CHARS) {
|
|
3594
|
+
const maxChars = options.maxChars == null ? null : Number(options.maxChars);
|
|
3595
|
+
if (maxChars !== null && (!Number.isInteger(maxChars) || maxChars < MIN_PROMPT_BUDGET_CHARS)) {
|
|
3449
3596
|
throw new RangeError(`Prompt budget must be an integer of at least ${MIN_PROMPT_BUDGET_CHARS} characters`);
|
|
3450
3597
|
}
|
|
3451
3598
|
const context = asRecord(input.context);
|
|
3452
|
-
const mode =
|
|
3599
|
+
const mode = promptContextMode(input);
|
|
3453
3600
|
const recoveryInstruction = recoveryInstructionText(input);
|
|
3454
3601
|
const recoveryContinuationOption = recoveryInstruction ? runtimeActionContinuationOptionText(input) : "";
|
|
3455
3602
|
const completeRecoveryInstruction = [recoveryInstruction, recoveryContinuationOption].filter(Boolean).join("\n\n");
|
|
@@ -3461,7 +3608,8 @@ function compileCommandPromptWithManifest(input, options = {}) {
|
|
|
3461
3608
|
const continuationSummary = continuationText(context);
|
|
3462
3609
|
const includeTask = mode === "cold" || !continuationSummary && asRecord(input.nativeSession).mode !== "governed_action_approval";
|
|
3463
3610
|
const wakeBodies = commentBodies(context);
|
|
3464
|
-
const
|
|
3611
|
+
const hasTaskCommentIds = Array.isArray(context.paperclipTaskMarkdownCommentIds);
|
|
3612
|
+
const commentsDuplicatedByTask = !hasTaskCommentIds && hasTask && wakeBodies.length > 0 && wakeBodies.every((body) => taskText.includes(body));
|
|
3465
3613
|
const commentsSelected = mode !== "cold" || !commentsDuplicatedByTask;
|
|
3466
3614
|
const interactionResolution = interactionResolutionText(context);
|
|
3467
3615
|
const selectedComments = commentsSelected ? readString(input.comments) ?? "" : "";
|
|
@@ -3507,11 +3655,11 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3507
3655
|
{ name: "continuation_summary", title: "Continuation Summary", priority: 97, sourceRef: readString(asRecord(context.paperclipContinuationSummary).key) ?? `issue:${input.issueId ?? "unknown"}`, observedAt: readString(asRecord(context.paperclipContinuationSummary).updatedAt), originalContent: continuationSummary, content: mode === "cold" ? "" : continuationSummary, truncationReason: mode === "cold" ? "mode_selection" : null },
|
|
3508
3656
|
...verifiedCompanyContext.content ? [{ name: "verified_company_context", title: "Verified Company Context", priority: 96, sourceRef: verifiedCompanyContext.sourceRef, observedAt: verifiedCompanyContext.observedAt, freshness: { kind: "run_snapshot" }, content: verifiedCompanyContext.content }] : [],
|
|
3509
3657
|
{ name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
|
|
3510
|
-
{ name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: taskText, content: includeTask ? taskText : "", truncationReason: includeTask ? null : "mode_selection" },
|
|
3658
|
+
{ name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n"), content: includeTask ? [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n") : "", truncationReason: includeTask ? null : "mode_selection" },
|
|
3511
3659
|
{ name: "governed_reads", title: "Governed External Reads", priority: 88, sourceRef: governedReads.provenance.map((entry) => entry.sourceRef), observedAt: governedReads.provenance.map((entry) => entry.observedAt), freshness: governedReads.provenance.map((entry) => entry.freshness), scope: governedReads.provenance.map((entry) => entry.scope), content: governedReads.content },
|
|
3512
3660
|
{ name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
|
|
3513
3661
|
{ name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
|
|
3514
|
-
{ name: "on_demand_refs", title: "On-demand Context References", priority: 70, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: onDemandRefs(input) },
|
|
3662
|
+
{ name: "on_demand_refs", title: "On-demand Context References", priority: 70, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: [onDemandRefs(input), overflowDependencyRefsText(resolvedDependencies.overflowRefs)].filter(Boolean).join("\n") },
|
|
3515
3663
|
{ name: "raw_snapshot", title: "Raw Context Snapshot", priority: 0, sourceRef: `run:${input.runId ?? "unknown"}`, originalChars: jsonCharLength(context), content: "", truncationReason: "on_demand_large_object" }
|
|
3516
3664
|
];
|
|
3517
3665
|
const seenContent = /* @__PURE__ */ new Set();
|
|
@@ -3535,6 +3683,14 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3535
3683
|
let prompt = "";
|
|
3536
3684
|
let compactManifest = false;
|
|
3537
3685
|
let manifest = buildManifest(mode, maxChars, sections, governedReads.provenance, 0);
|
|
3686
|
+
if (maxChars === null) {
|
|
3687
|
+
for (let telemetryPass = 0; telemetryPass < 20; telemetryPass += 1) {
|
|
3688
|
+
prompt = renderPrompt(sections, manifest);
|
|
3689
|
+
if (manifest.budget.usedChars === prompt.length) return { prompt, manifest };
|
|
3690
|
+
manifest = buildManifest(mode, null, sections, governedReads.provenance, prompt.length);
|
|
3691
|
+
}
|
|
3692
|
+
throw new Error("Prompt compiler could not stabilize the unbounded Context Manifest");
|
|
3693
|
+
}
|
|
3538
3694
|
for (let pass = 0; pass < 20; pass += 1) {
|
|
3539
3695
|
let usedChars = 0;
|
|
3540
3696
|
for (let telemetryPass = 0; telemetryPass < 3; telemetryPass += 1) {
|
|
@@ -3557,17 +3713,24 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3557
3713
|
const fixedChars = sections.filter((section) => section.priority === 100).map(sectionText).join("\n").length;
|
|
3558
3714
|
const manifestChars = JSON.stringify(manifest).length;
|
|
3559
3715
|
if (resolvedDependencies.required.tupleCount > 0) {
|
|
3560
|
-
throw
|
|
3716
|
+
throw promptBudgetError(
|
|
3717
|
+
"resolved_dependencies_budget_exceeded",
|
|
3561
3718
|
`Resolved dependency mandatory read tuples exceed the unified ${maxChars}-character prompt budget: tupleCount=${resolvedDependencies.required.tupleCount} promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`
|
|
3562
3719
|
);
|
|
3563
3720
|
}
|
|
3564
|
-
throw
|
|
3721
|
+
throw promptBudgetError(
|
|
3722
|
+
"prompt_budget_exceeded",
|
|
3723
|
+
`Prompt fixed sections exceed the unified ${maxChars}-character budget: promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`
|
|
3724
|
+
);
|
|
3565
3725
|
}
|
|
3566
3726
|
truncateSection(candidate, Math.max(0, candidate.content.length - overflow - 32));
|
|
3567
3727
|
manifest = buildManifest(mode, maxChars, sections, governedReads.provenance, 0);
|
|
3568
3728
|
}
|
|
3569
3729
|
if (prompt.length > maxChars || manifest.budget.usedChars !== prompt.length) {
|
|
3570
|
-
throw
|
|
3730
|
+
throw promptBudgetError(
|
|
3731
|
+
"prompt_budget_exceeded",
|
|
3732
|
+
`Prompt compiler could not satisfy the unified ${maxChars}-character budget`
|
|
3733
|
+
);
|
|
3571
3734
|
}
|
|
3572
3735
|
return { prompt, manifest };
|
|
3573
3736
|
}
|
|
@@ -4370,6 +4533,7 @@ var CODEX_USAGE_LIMIT_RE = /you(?:'|’)ve hit your usage limit for .+\.\s+switc
|
|
|
4370
4533
|
var PI_PROVIDER_AUTH_RE = /(?:(?:\b401\b|\b403\b)[^\n]*(?:unauthorized|forbidden|auth(?:entication|orization)?|api[_\s-]?key)|(?:invalid|missing|expired|revoked)\s+(?:provider\s+)?api[_\s-]?key|provider\s+authentication\s+required)/i;
|
|
4371
4534
|
var PI_PROVIDER_QUOTA_EXHAUSTED_RE = /(?:\binsufficient[_\s-]?user[_\s-]?quota\b|河狸币余额不足|\b402\b[^\n]*(?:余额不足|payment\s+required))/i;
|
|
4372
4535
|
var PI_PROVIDER_TRANSIENT_RE = /(?:\b(?:429|5\d{2})\b|rate[-\s]?limit(?:ed)?|too\s+many\s+requests|billing\s+admission\s+failed|service\s+unavailable|upstream[^\n]*(?:unavailable|failed|timeout)|connect(?:ion)?[^\n]*refused|temporar(?:y|ily)[^\n]*(?:unavailable|failed)|try\s+again\s+later)/i;
|
|
4536
|
+
var PI_PROVIDER_PROTOCOL_RE = /provider[^\n]*finish_reason[^\n]*unexpected_state/i;
|
|
4373
4537
|
var PI_PROVIDER_RETRY_AFTER_SECONDS_RE = /retry[-\s]?after\s*[:=]?\s*(\d{1,6})\s*(?:seconds?|secs?|s)\b/i;
|
|
4374
4538
|
var PI_TERMINAL_CLEANUP_PERMISSION_RE = /(?:\bkill\b[^\n]*\bEPERM\b|\bEPERM\b[^\n]*\bkill\b)/i;
|
|
4375
4539
|
var MAX_PI_PROVIDER_RETRY_AFTER_SECONDS = 7 * 24 * 60 * 60;
|
|
@@ -4712,6 +4876,12 @@ function extractPiProviderRetryNotBefore(errorMessage, now) {
|
|
|
4712
4876
|
function classifyPiProviderError(input, now = /* @__PURE__ */ new Date()) {
|
|
4713
4877
|
const errorMessage = readString(asRecord(input).errorMessage);
|
|
4714
4878
|
if (!errorMessage) return null;
|
|
4879
|
+
if (PI_PROVIDER_PROTOCOL_RE.test(errorMessage)) {
|
|
4880
|
+
return {
|
|
4881
|
+
errorCode: "pi_provider_protocol_failure",
|
|
4882
|
+
errorFamily: "provider_protocol"
|
|
4883
|
+
};
|
|
4884
|
+
}
|
|
4715
4885
|
if (PI_PROVIDER_QUOTA_EXHAUSTED_RE.test(errorMessage)) {
|
|
4716
4886
|
return {
|
|
4717
4887
|
errorCode: "pi_provider_quota_exhausted",
|
|
@@ -4956,13 +5126,17 @@ function parsePiJsonl(stdout) {
|
|
|
4956
5126
|
let hasAssistantOutput = false;
|
|
4957
5127
|
let nonCleanupErrorCount = 0;
|
|
4958
5128
|
let nonCleanupErrorMessage = null;
|
|
5129
|
+
let terminalEventIndex = null;
|
|
5130
|
+
let eventIndex = -1;
|
|
4959
5131
|
const messages = [];
|
|
4960
5132
|
const mcpToolResults = [];
|
|
4961
5133
|
const cleanupDiagnostics = [];
|
|
5134
|
+
const diagnostics = [];
|
|
4962
5135
|
const usage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
|
|
4963
5136
|
for (const rawLine of String(stdout ?? "").split(/\r?\n/)) {
|
|
4964
5137
|
const event = parseJsonLine(rawLine.trim());
|
|
4965
5138
|
if (!event) continue;
|
|
5139
|
+
eventIndex += 1;
|
|
4966
5140
|
mcpToolResults.push(...piMcpToolResults(event));
|
|
4967
5141
|
if (event.type === "session") {
|
|
4968
5142
|
sessionId = readString(event.sessionId) ?? readString(event.id) ?? sessionId;
|
|
@@ -4987,13 +5161,26 @@ function parsePiJsonl(stdout) {
|
|
|
4987
5161
|
}
|
|
4988
5162
|
if (["message", "message_update", "message_end", "turn_end", "agent_end"].includes(event.type)) {
|
|
4989
5163
|
if (event.type === "turn_end") sawTurnEnd = true;
|
|
4990
|
-
if (event.type === "turn_end" || event.type === "agent_end")
|
|
5164
|
+
if (event.type === "turn_end" || event.type === "agent_end") {
|
|
5165
|
+
terminalEventType = event.type;
|
|
5166
|
+
terminalEventIndex = eventIndex;
|
|
5167
|
+
}
|
|
4991
5168
|
stopReason = readString(event.stopReason ?? event.stop_reason) ?? piNestedMessageStopReason(event) ?? stopReason;
|
|
4992
5169
|
const terminalError = piStopReasonErrorText(event) ?? piNestedMessageErrorText(event);
|
|
4993
5170
|
if (terminalError) {
|
|
4994
5171
|
nonCleanupErrorCount += 1;
|
|
4995
5172
|
nonCleanupErrorMessage = terminalError;
|
|
4996
5173
|
errorMessage = terminalError;
|
|
5174
|
+
if (PI_PROVIDER_PROTOCOL_RE.test(terminalError)) {
|
|
5175
|
+
diagnostics.push({
|
|
5176
|
+
source: "provider",
|
|
5177
|
+
phase: "terminal",
|
|
5178
|
+
severity: "error",
|
|
5179
|
+
code: "pi_provider_protocol_failure",
|
|
5180
|
+
message: terminalError,
|
|
5181
|
+
eventIndex
|
|
5182
|
+
});
|
|
5183
|
+
}
|
|
4997
5184
|
}
|
|
4998
5185
|
hasAssistantOutput = maybeCapturePiMessage(event, messages, usage) || hasAssistantOutput;
|
|
4999
5186
|
continue;
|
|
@@ -5002,16 +5189,33 @@ function parsePiJsonl(stdout) {
|
|
|
5002
5189
|
const eventError = readString(event.message);
|
|
5003
5190
|
if (!eventError) continue;
|
|
5004
5191
|
if (PI_TERMINAL_CLEANUP_PERMISSION_RE.test(eventError)) {
|
|
5005
|
-
|
|
5192
|
+
const diagnostic = {
|
|
5006
5193
|
code: "pi_terminal_cleanup_permission_denied",
|
|
5007
5194
|
message: eventError,
|
|
5008
5195
|
phase: terminalEventType === "agent_end" ? "post_terminal" : "pre_terminal"
|
|
5196
|
+
};
|
|
5197
|
+
cleanupDiagnostics.push(diagnostic);
|
|
5198
|
+
diagnostics.push({
|
|
5199
|
+
source: "executor",
|
|
5200
|
+
severity: "warning",
|
|
5201
|
+
...diagnostic,
|
|
5202
|
+
eventIndex
|
|
5009
5203
|
});
|
|
5010
5204
|
errorMessage = nonCleanupErrorMessage ?? eventError;
|
|
5011
5205
|
} else {
|
|
5012
5206
|
nonCleanupErrorCount += 1;
|
|
5013
5207
|
nonCleanupErrorMessage = eventError;
|
|
5014
5208
|
errorMessage = eventError;
|
|
5209
|
+
if (PI_PROVIDER_PROTOCOL_RE.test(eventError)) {
|
|
5210
|
+
diagnostics.push({
|
|
5211
|
+
source: "provider",
|
|
5212
|
+
phase: terminalEventType === "agent_end" ? "post_terminal" : "pre_terminal",
|
|
5213
|
+
severity: "error",
|
|
5214
|
+
code: "pi_provider_protocol_failure",
|
|
5215
|
+
message: eventError,
|
|
5216
|
+
eventIndex
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5015
5219
|
}
|
|
5016
5220
|
}
|
|
5017
5221
|
}
|
|
@@ -5022,11 +5226,13 @@ function parsePiJsonl(stdout) {
|
|
|
5022
5226
|
usage,
|
|
5023
5227
|
sawTurnEnd,
|
|
5024
5228
|
terminalEventType,
|
|
5229
|
+
terminalEventIndex,
|
|
5025
5230
|
stopReason,
|
|
5026
5231
|
hasAssistantOutput,
|
|
5027
5232
|
errorMessage,
|
|
5028
5233
|
...nonCleanupErrorCount > 0 ? { nonCleanupErrorCount } : {},
|
|
5029
5234
|
...cleanupDiagnostics.length > 0 ? { cleanupDiagnostics } : {},
|
|
5235
|
+
...diagnostics.length > 0 ? { diagnostics } : {},
|
|
5030
5236
|
...uniqueMcpToolResults.length > 0 ? { mcpToolResults: uniqueMcpToolResults } : {}
|
|
5031
5237
|
};
|
|
5032
5238
|
}
|
|
@@ -6729,6 +6935,7 @@ var ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Map([
|
|
|
6729
6935
|
[".jpeg", "image"],
|
|
6730
6936
|
[".webp", "image"],
|
|
6731
6937
|
[".gif", "image"],
|
|
6938
|
+
[".svg", "image"],
|
|
6732
6939
|
[".mp4", "video"],
|
|
6733
6940
|
[".m4v", "video"],
|
|
6734
6941
|
[".mov", "video"],
|
|
@@ -6766,7 +6973,7 @@ function isSafeRelativePath(value) {
|
|
|
6766
6973
|
const text = String(value ?? "").trim().split(/[\\/]+/).join("/");
|
|
6767
6974
|
if (!text || text.startsWith("../") || text === ".." || text.startsWith("/")) return false;
|
|
6768
6975
|
const segments = text.split("/").filter(Boolean);
|
|
6769
|
-
return !SECRET_PATH_PATTERN.test(text) && !RUNTIME_INSTRUCTION_FILENAMES.has(basename5(text)) && !segments.some((segment) => segment === ".venv" || segment === "venv");
|
|
6976
|
+
return !SECRET_PATH_PATTERN.test(text) && !RUNTIME_INSTRUCTION_FILENAMES.has(basename5(text)) && !segments.some((segment) => segment.startsWith(".")) && !segments.some((segment) => segment === ".venv" || segment === "venv");
|
|
6770
6977
|
}
|
|
6771
6978
|
function gitStatusPath(line) {
|
|
6772
6979
|
if (line.startsWith("?? ")) return line.slice(3);
|
|
@@ -6840,8 +7047,7 @@ function scanArtifactCandidates(cwd, opts = {}) {
|
|
|
6840
7047
|
}
|
|
6841
7048
|
if (!entry.isFile()) continue;
|
|
6842
7049
|
const ext = extname(entry.name).toLowerCase();
|
|
6843
|
-
const type = ARTIFACT_EXTENSIONS.get(ext);
|
|
6844
|
-
if (!type) continue;
|
|
7050
|
+
const type = ARTIFACT_EXTENSIONS.get(ext) ?? "file";
|
|
6845
7051
|
let stat;
|
|
6846
7052
|
try {
|
|
6847
7053
|
stat = statSync6(fullPath);
|
|
@@ -8698,11 +8904,10 @@ function createPublicNetworkScope(options = {}) {
|
|
|
8698
8904
|
}
|
|
8699
8905
|
|
|
8700
8906
|
// src/amaster-runtime-daemon.mjs
|
|
8701
|
-
var CONNECTOR_VERSION = "0.1.0-beta.
|
|
8907
|
+
var CONNECTOR_VERSION = "0.1.0-beta.54";
|
|
8702
8908
|
var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
|
|
8703
8909
|
var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
|
|
8704
8910
|
var CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8705
|
-
var PROMPT_AGENT_INSTRUCTION_FILE_ORDER = ["AGENTS.md", "SOUL.md"];
|
|
8706
8911
|
var AMASTER_PI_PROHIBITED_EXTRA_ARGS = /* @__PURE__ */ new Set(["--no-extensions", "--no-skills", "--no-tools", "--no-session"]);
|
|
8707
8912
|
var MAX_PI_CAPABILITY_SOURCE_ENTRIES = 200;
|
|
8708
8913
|
var PI_COMPLETION_OUTPUT_GRACE_MS = 1e3;
|
|
@@ -9823,51 +10028,46 @@ function renderIssueLine(context) {
|
|
|
9823
10028
|
const title = readString(issue.title);
|
|
9824
10029
|
return [identifier, title].filter(Boolean).join(" ");
|
|
9825
10030
|
}
|
|
9826
|
-
function renderComments(context) {
|
|
10031
|
+
function renderComments(context, options = {}) {
|
|
9827
10032
|
const wake = asRecord(context.paperclipWake);
|
|
9828
10033
|
const comments = Array.isArray(wake.comments) ? wake.comments : [];
|
|
10034
|
+
const issueId = readString(options.issueId) ?? "";
|
|
10035
|
+
let truncatedCount = 0;
|
|
9829
10036
|
const rendered = comments.map((entry, index) => {
|
|
9830
10037
|
const comment = asRecord(entry);
|
|
9831
10038
|
const id = readString(comment.id) ?? `comment-${index + 1}`;
|
|
9832
10039
|
const body = readString(comment.body) ?? "";
|
|
9833
|
-
const
|
|
9834
|
-
|
|
10040
|
+
const truncated = comment.bodyTruncated === true;
|
|
10041
|
+
if (truncated) truncatedCount += 1;
|
|
10042
|
+
const truncatedNote = truncated ? `
|
|
10043
|
+
[comment body truncated \u2014 fetch the full text before relying on it: comment:${id}]` : "";
|
|
9835
10044
|
return `${index + 1}. ${id}
|
|
9836
10045
|
${body}${truncatedNote}`;
|
|
9837
10046
|
}).filter((entry) => entry.trim().length > 0).join("\n\n");
|
|
9838
|
-
const
|
|
9839
|
-
|
|
10047
|
+
const guidance = [];
|
|
10048
|
+
if (truncatedCount > 0 && issueId) {
|
|
10049
|
+
guidance.push(
|
|
10050
|
+
`Truncated comments above are marked comment:<id>. Fetch the full text before relying on a truncated comment \u2014 ${readIssueEvidenceCommentCallText(issueId, "<id>", options)} (replace <id> with the referenced comment id).`
|
|
10051
|
+
);
|
|
10052
|
+
}
|
|
10053
|
+
if (wake.fallbackFetchNeeded === true) {
|
|
10054
|
+
guidance.push(
|
|
10055
|
+
"[some wake comments were truncated or omitted from this prompt \u2014 fetch full text via amaster.read_issue_evidence using the comment:<id> references]"
|
|
10056
|
+
);
|
|
10057
|
+
}
|
|
10058
|
+
return [rendered, ...guidance].filter(Boolean).join("\n\n");
|
|
9840
10059
|
}
|
|
9841
10060
|
function renderTaskMarkdown(context) {
|
|
9842
10061
|
return readString(context.paperclipTaskMarkdown);
|
|
9843
10062
|
}
|
|
9844
|
-
function normalizeAgentInstructionsFiles(bundle) {
|
|
9845
|
-
const files = asRecord(bundle.files);
|
|
9846
|
-
const selected = [];
|
|
9847
|
-
const seen = /* @__PURE__ */ new Set();
|
|
9848
|
-
for (const path of PROMPT_AGENT_INSTRUCTION_FILE_ORDER) {
|
|
9849
|
-
const content = readString(files[path]);
|
|
9850
|
-
if (!content) continue;
|
|
9851
|
-
selected.push({ path, content });
|
|
9852
|
-
seen.add(path);
|
|
9853
|
-
}
|
|
9854
|
-
const entryFile = readString(bundle.entryFile);
|
|
9855
|
-
if (entryFile && !seen.has(entryFile)) {
|
|
9856
|
-
const content = readString(files[entryFile]);
|
|
9857
|
-
if (content) {
|
|
9858
|
-
selected.push({ path: entryFile, content });
|
|
9859
|
-
seen.add(entryFile);
|
|
9860
|
-
}
|
|
9861
|
-
}
|
|
9862
|
-
return selected;
|
|
9863
|
-
}
|
|
9864
10063
|
function renderAgentInstructionsBundle(bundle) {
|
|
9865
|
-
const files =
|
|
9866
|
-
|
|
10064
|
+
const files = asRecord(asRecord(bundle).files);
|
|
10065
|
+
const names = Object.keys(files).filter((path) => readString(files[path])).sort((left, right) => left === right ? 0 : left === "AGENTS.md" ? -1 : right === "AGENTS.md" ? 1 : left.localeCompare(right));
|
|
10066
|
+
if (names.length === 0) return "";
|
|
9867
10067
|
return [
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
].join("\n
|
|
10068
|
+
`Current agent instructions are materialized in the execution workspace as: ${names.map((name) => `./${name}`).join(", ")}.`,
|
|
10069
|
+
"They are authoritative for this run and are not inlined here. Read ./AGENTS.md first and follow it (including any sibling files it references) for the whole run."
|
|
10070
|
+
].join("\n");
|
|
9871
10071
|
}
|
|
9872
10072
|
function commandRuntimeAuth(command) {
|
|
9873
10073
|
const topLevel = asRecord(command.runtimeAuth);
|
|
@@ -10018,13 +10218,44 @@ async function materializeAgentInstructionsBundle(config, command, workspace) {
|
|
|
10018
10218
|
}
|
|
10019
10219
|
return materialized;
|
|
10020
10220
|
}
|
|
10221
|
+
function wikiTreePathForCommand(command, workspaceBindings) {
|
|
10222
|
+
const runtimeAuth = commandRuntimeAuth(command);
|
|
10223
|
+
const companyId = readString(runtimeAuth.companyId) ?? readString(asRecord(command.payload).companyId) ?? "";
|
|
10224
|
+
for (const binding of Array.isArray(workspaceBindings) ? workspaceBindings : []) {
|
|
10225
|
+
const root = readString(binding);
|
|
10226
|
+
if (!root) continue;
|
|
10227
|
+
const candidates = [];
|
|
10228
|
+
if (root.endsWith("paperclipai.plugin-llm-wiki")) candidates.push(root);
|
|
10229
|
+
if (basename6(root) === "plugin-data" && companyId) {
|
|
10230
|
+
candidates.push(join15(root, companyId, "paperclipai.plugin-llm-wiki"));
|
|
10231
|
+
}
|
|
10232
|
+
for (const candidate of candidates) {
|
|
10233
|
+
try {
|
|
10234
|
+
if (existsSync14(candidate)) return candidate;
|
|
10235
|
+
} catch {
|
|
10236
|
+
}
|
|
10237
|
+
}
|
|
10238
|
+
}
|
|
10239
|
+
return null;
|
|
10240
|
+
}
|
|
10021
10241
|
function buildCommandPrompt(command, workspace, materializedAttachments = [], options = {}) {
|
|
10022
10242
|
const workspaceContext = normalizeWorkspaceContext(workspace);
|
|
10023
10243
|
const cwd = workspaceContext.cwd;
|
|
10024
10244
|
const payload = asRecord(command.payload);
|
|
10025
10245
|
const context = asRecord(payload.contextSnapshot);
|
|
10026
10246
|
const issueLine = renderIssueLine(context);
|
|
10027
|
-
const comments = renderComments(
|
|
10247
|
+
const comments = renderComments(
|
|
10248
|
+
filterDuplicatedTaskComments(context, promptContextMode({
|
|
10249
|
+
nativeSession: asRecord(payload.nativeSession),
|
|
10250
|
+
wakeReason: readString(context.wakeReason),
|
|
10251
|
+
context
|
|
10252
|
+
})),
|
|
10253
|
+
{
|
|
10254
|
+
executorKind: options.executorKind,
|
|
10255
|
+
managedMcpToolMode: options.managedMcpToolMode,
|
|
10256
|
+
issueId: commandIssueId(command)
|
|
10257
|
+
}
|
|
10258
|
+
);
|
|
10028
10259
|
const taskMarkdown = renderTaskMarkdown(context);
|
|
10029
10260
|
const agentInstructions = renderAgentInstructionsBundle(asRecord(payload.agentInstructionsBundle));
|
|
10030
10261
|
const runtimeAuth = commandRuntimeAuth(command);
|
|
@@ -10064,7 +10295,11 @@ function buildCommandPrompt(command, workspace, materializedAttachments = [], op
|
|
|
10064
10295
|
attachmentsText,
|
|
10065
10296
|
comments,
|
|
10066
10297
|
context,
|
|
10067
|
-
nativeSession: asRecord(payload.nativeSession)
|
|
10298
|
+
nativeSession: asRecord(payload.nativeSession),
|
|
10299
|
+
wikiAccess: {
|
|
10300
|
+
tools: context.wikiToolsAvailable === true,
|
|
10301
|
+
treePath: wikiTreePathForCommand(command, options.workspaceBindings)
|
|
10302
|
+
}
|
|
10068
10303
|
});
|
|
10069
10304
|
}
|
|
10070
10305
|
function companyPiHomeRoot(baseEnv) {
|
|
@@ -12812,7 +13047,8 @@ async function executeRunCommand(config, command) {
|
|
|
12812
13047
|
const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
|
|
12813
13048
|
executorKind: executor.kind,
|
|
12814
13049
|
managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? MANAGED_PI_MCP_TOOL_MODE : null,
|
|
12815
|
-
artifactVerifierCommands: config.artifactVerifierCommands
|
|
13050
|
+
artifactVerifierCommands: config.artifactVerifierCommands,
|
|
13051
|
+
workspaceBindings: config.workspaceBindings
|
|
12816
13052
|
});
|
|
12817
13053
|
const nativeSessionRequest = asRecord(asRecord(command.payload).nativeSession);
|
|
12818
13054
|
const prompt = promptCompilation.prompt;
|
|
@@ -13030,7 +13266,8 @@ async function executeRunCommand(config, command) {
|
|
|
13030
13266
|
...piCompanyMemory ? { companyMemory: piCompanyMemory.attestation } : {}
|
|
13031
13267
|
});
|
|
13032
13268
|
}
|
|
13033
|
-
|
|
13269
|
+
const promptBudgetSummary = contextManifest.budget.totalChars === null ? `${contextManifest.budget.usedChars} characters (unbounded)` : `${contextManifest.budget.usedChars}/${contextManifest.budget.totalChars} characters`;
|
|
13270
|
+
await ingestLog(config, command, "system", "info", `Compiled ${contextManifest.mode} prompt using ${promptBudgetSummary}`, {
|
|
13034
13271
|
presentationKind: "context_manifest",
|
|
13035
13272
|
contextManifest
|
|
13036
13273
|
});
|
|
@@ -13253,17 +13490,17 @@ async function executeRunCommand(config, command) {
|
|
|
13253
13490
|
command,
|
|
13254
13491
|
"system",
|
|
13255
13492
|
"warn",
|
|
13256
|
-
"Pi
|
|
13493
|
+
"Pi reported a post-terminal cleanup permission failure; server disposition evaluation remains authoritative",
|
|
13257
13494
|
{
|
|
13258
13495
|
presentationKind: "pi_terminal_cleanup",
|
|
13259
13496
|
cleanupDisposition
|
|
13260
13497
|
}
|
|
13261
13498
|
);
|
|
13262
13499
|
}
|
|
13263
|
-
const parsedForValidation =
|
|
13500
|
+
const parsedForValidation = parsed;
|
|
13264
13501
|
const piTurnLimitFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiTurnLimitResult(parsedForValidation) : null;
|
|
13265
13502
|
const piInvalidOutputError = executor.kind === "pi" ? piOutputValidationError(parsedForValidation, {
|
|
13266
|
-
allowMissingTurnEnd: completionOutputStopped
|
|
13503
|
+
allowMissingTurnEnd: completionOutputStopped,
|
|
13267
13504
|
allowMissingAssistantOutput: execution.completionOutputType === "approval_required"
|
|
13268
13505
|
}) : null;
|
|
13269
13506
|
const piProviderFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiProviderError(parsedForValidation) : null;
|
|
@@ -13273,13 +13510,22 @@ async function executeRunCommand(config, command) {
|
|
|
13273
13510
|
stderr: execution.stderr,
|
|
13274
13511
|
errorMessage: parsedErrorMessage
|
|
13275
13512
|
}) : null;
|
|
13276
|
-
const succeeded = !cancelled && !hasOutputFlood && !hasMemoryLimit && (execution.exitCode === 0 || completionOutputStopped
|
|
13513
|
+
const succeeded = !cancelled && !hasOutputFlood && !hasMemoryLimit && (execution.exitCode === 0 || completionOutputStopped) && !execution.timedOut && !execution.spawnError && !parsedErrorMessage;
|
|
13277
13514
|
const resultStderr = filterExecutionStderrForResult(executor.kind, execution.stderr);
|
|
13278
13515
|
const error = execution.timedOut ? `Executor timed out after ${config.executorTimeoutSeconds}s` : cancelled ? "Executor cancelled by AMaster control plane" : execution.spawnError ?? parsedErrorMessage ?? (succeeded ? null : `Executor exited with code ${execution.exitCode ?? "unknown"}`);
|
|
13279
13516
|
const costUsage = parsedCostUsage(parsed.usage);
|
|
13517
|
+
const executorOutcome = {
|
|
13518
|
+
status: cancelled ? "cancelled" : execution.timedOut ? "timed_out" : execution.exitCode === 0 && execution.signal === null ? "completed" : "failed",
|
|
13519
|
+
exitCode: execution.exitCode,
|
|
13520
|
+
signal: execution.signal,
|
|
13521
|
+
terminalEvent: ["agent_end", "turn_end"].includes(readString(parsed.terminalEventType) ?? "") ? readString(parsed.terminalEventType) : null,
|
|
13522
|
+
terminalEventIndex: Number.isInteger(parsed.terminalEventIndex) ? parsed.terminalEventIndex : null
|
|
13523
|
+
};
|
|
13280
13524
|
let result3 = {
|
|
13281
13525
|
evidenceContract: { version: 1 },
|
|
13282
13526
|
executorKind: executor.kind,
|
|
13527
|
+
executorOutcome,
|
|
13528
|
+
...Array.isArray(parsed.diagnostics) && parsed.diagnostics.length > 0 ? { diagnostics: parsed.diagnostics } : {},
|
|
13283
13529
|
command: invocation.command,
|
|
13284
13530
|
args: invocation.args,
|
|
13285
13531
|
cwd,
|
package/dist/amaster-runtime.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
5
5
|
import { homedir, hostname } from "node:os";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
|
-
const CONNECTOR_VERSION = "0.1.0-beta.
|
|
8
|
+
const CONNECTOR_VERSION = "0.1.0-beta.54";
|
|
9
9
|
|
|
10
10
|
const CAPABILITIES = [
|
|
11
11
|
"remote_registration",
|