@amaster.ai/employee-runtime-connector 0.1.0-beta.53 → 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 +251 -61
- 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;
|
|
@@ -2247,6 +2321,12 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2247
2321
|
};
|
|
2248
2322
|
writePrivateFile2(join4(agentDir, "settings.json"), `${JSON.stringify(settings, null, 2)}
|
|
2249
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
|
+
);
|
|
2250
2330
|
copyPrivateFile(join4(source, "models.json"), join4(agentDir, "models.json"));
|
|
2251
2331
|
const authSource = join4(source, "auth.json");
|
|
2252
2332
|
const protectedValues = [];
|
|
@@ -2395,6 +2475,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2395
2475
|
...executorAttestation,
|
|
2396
2476
|
mcpAdapterVersion: seededRuntime.adapterVersion,
|
|
2397
2477
|
mcpToolMode: MANAGED_PI_MCP_TOOL_MODE,
|
|
2478
|
+
mcpArgsNormalization: MANAGED_PI_MCP_ARGS_NORMALIZATION,
|
|
2398
2479
|
configMode: "isolated_home_run_scoped_mcp_file",
|
|
2399
2480
|
namespace: SUPPORTED_SERVER_NAME2,
|
|
2400
2481
|
schemaVersion: SUPPORTED_SCHEMA_VERSION2,
|
|
@@ -2910,8 +2991,14 @@ function removeRunCompletionState(directory, commandId) {
|
|
|
2910
2991
|
}
|
|
2911
2992
|
|
|
2912
2993
|
// src/amaster-runtime-daemon/prompt-compiler.mjs
|
|
2913
|
-
var DEADLINE_POSTURE_GUARD = "
|
|
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.";
|
|
2914
2995
|
var MIN_PROMPT_BUDGET_CHARS = 8192;
|
|
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
|
+
}
|
|
2915
3002
|
var CONTINUATION_WAKE_PATTERN = /(continuation|continued|retry|approved|liveness|resume|max_turn)/i;
|
|
2916
3003
|
var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
|
|
2917
3004
|
"finish_successful_run_handoff",
|
|
@@ -2933,7 +3020,7 @@ function jsonCharLength(value) {
|
|
|
2933
3020
|
function estimatedTokens(chars) {
|
|
2934
3021
|
return Math.ceil(chars / 4);
|
|
2935
3022
|
}
|
|
2936
|
-
function
|
|
3023
|
+
function promptContextMode(input) {
|
|
2937
3024
|
const nativeSession = asRecord(input.nativeSession);
|
|
2938
3025
|
if (nativeSession.mode === "governed_action_approval" || readString(input.context?.resumeFromRunId) || isRecoveryWakeReason(input.wakeReason) || CONTINUATION_WAKE_PATTERN.test(input.wakeReason ?? "")) return "continuation";
|
|
2939
3026
|
if (nativeSession.resume === true || Object.keys(asRecord(input.context?.paperclipContinuationSummary)).length > 0) {
|
|
@@ -2941,6 +3028,22 @@ function contextMode(input) {
|
|
|
2941
3028
|
}
|
|
2942
3029
|
return "cold";
|
|
2943
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
|
+
}
|
|
2944
3047
|
function commentRefs(context) {
|
|
2945
3048
|
const comments = Array.isArray(asRecord(context.paperclipWake).comments) ? asRecord(context.paperclipWake).comments : [];
|
|
2946
3049
|
return comments.map((entry) => readString(asRecord(entry).id)).filter(Boolean);
|
|
@@ -3036,6 +3139,7 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3036
3139
|
}
|
|
3037
3140
|
const summaries = contextCopy ?? wakeCopy ?? [];
|
|
3038
3141
|
const tuples = [];
|
|
3142
|
+
const overflowRefs = [];
|
|
3039
3143
|
const seenTuples = /* @__PURE__ */ new Set();
|
|
3040
3144
|
const detailLines = [];
|
|
3041
3145
|
const detailSourceRefs = [];
|
|
@@ -3086,15 +3190,19 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3086
3190
|
]);
|
|
3087
3191
|
if (seenTuples.has(tupleKey)) continue;
|
|
3088
3192
|
seenTuples.add(tupleKey);
|
|
3089
|
-
tuples.
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
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
|
+
}
|
|
3098
3206
|
const documentTitle = readString(document.title);
|
|
3099
3207
|
detailLines.push(
|
|
3100
3208
|
` Document: ${key}${documentTitle ? ` (${documentTitle})` : ""}${latestRevisionNumber != null ? ` revision ${latestRevisionNumber}` : ""}`
|
|
@@ -3113,6 +3221,11 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3113
3221
|
if (workProductSummary) detailLines.push(` ${workProductSummary}`);
|
|
3114
3222
|
}
|
|
3115
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
|
+
}
|
|
3116
3229
|
const requiredLines = tuples.length > 0 ? [
|
|
3117
3230
|
"Accepted predecessor outputs are binding inputs unless this issue explicitly requests reconsideration.",
|
|
3118
3231
|
"Before any downstream document/artifact write, review request, status mutation, or completion, perform every Required read.",
|
|
@@ -3148,7 +3261,8 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
|
|
|
3148
3261
|
observedAt: detailObservedAt,
|
|
3149
3262
|
freshness: detailSourceRefs.map(() => snapshotFreshness),
|
|
3150
3263
|
scope: detailSourceRefs.map(() => contextScope)
|
|
3151
|
-
}
|
|
3264
|
+
},
|
|
3265
|
+
overflowRefs
|
|
3152
3266
|
};
|
|
3153
3267
|
}
|
|
3154
3268
|
function verifiedCompanyContextSection(context) {
|
|
@@ -3180,12 +3294,29 @@ function verifiedCompanyContextSection(context) {
|
|
|
3180
3294
|
].filter(Boolean)
|
|
3181
3295
|
};
|
|
3182
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
|
+
}
|
|
3183
3312
|
function fixedRules(input, includeIssueLine) {
|
|
3184
3313
|
return [
|
|
3185
3314
|
"## AMaster Runtime Connector Task",
|
|
3186
3315
|
"MirrorX task.",
|
|
3187
3316
|
"Use only the declared workspace; make concrete progress and report concisely.",
|
|
3188
|
-
"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.",
|
|
3189
3320
|
DEADLINE_POSTURE_GUARD,
|
|
3190
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.",
|
|
3191
3322
|
`- command id: ${input.commandId}`,
|
|
@@ -3198,9 +3329,10 @@ function fixedRules(input, includeIssueLine) {
|
|
|
3198
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." : "",
|
|
3199
3330
|
input.wakeReason ? `- wake reason: ${input.wakeReason}` : "",
|
|
3200
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),
|
|
3201
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.",
|
|
3202
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.",
|
|
3203
|
-
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." : ""
|
|
3204
3336
|
].filter(Boolean).join("\n");
|
|
3205
3337
|
}
|
|
3206
3338
|
function approvalContinuationText(input) {
|
|
@@ -3360,6 +3492,25 @@ function runtimeDecompositionRequirementText(context) {
|
|
|
3360
3492
|
`Requirement source: ${sourceType}:${sourceId}@${sourceRevision}`
|
|
3361
3493
|
].join("\n");
|
|
3362
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
|
+
}
|
|
3363
3514
|
function piMcpProxyExamplesText(input) {
|
|
3364
3515
|
if (!input.hasGovernedMcp || input.executorKind !== "pi" || input.managedMcpToolMode !== "proxy_only" || isRecoveryWakeReason(input.wakeReason)) return "";
|
|
3365
3516
|
const proxy = (tool, args) => JSON.stringify({
|
|
@@ -3370,10 +3521,11 @@ function piMcpProxyExamplesText(input) {
|
|
|
3370
3521
|
return [
|
|
3371
3522
|
"The Pi native tool is the outer `mcp` proxy. Emit these as actual tool calls; `args` is the stringified inner canonical object:",
|
|
3372
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.",
|
|
3373
3525
|
`- describe: ${proxy("runtime_action.describe", { schemaVersion: "runtime-action-v1", actionType: "update_parent" })}`,
|
|
3374
|
-
`- 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" } })}`,
|
|
3375
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 } } } })}`,
|
|
3376
|
-
`- 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" }] })}`,
|
|
3377
3529
|
`- commit the returned plan revision: ${proxy("runtime_action.commit", { schemaVersion: "runtime-action-v1", planId: "11111111-1111-4111-8111-111111111111", revision: "plan-revision-1" })}`,
|
|
3378
3530
|
`- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`
|
|
3379
3531
|
].join("\n");
|
|
@@ -3444,7 +3596,7 @@ function compileCommandPromptWithManifest(input, options = {}) {
|
|
|
3444
3596
|
throw new RangeError(`Prompt budget must be an integer of at least ${MIN_PROMPT_BUDGET_CHARS} characters`);
|
|
3445
3597
|
}
|
|
3446
3598
|
const context = asRecord(input.context);
|
|
3447
|
-
const mode =
|
|
3599
|
+
const mode = promptContextMode(input);
|
|
3448
3600
|
const recoveryInstruction = recoveryInstructionText(input);
|
|
3449
3601
|
const recoveryContinuationOption = recoveryInstruction ? runtimeActionContinuationOptionText(input) : "";
|
|
3450
3602
|
const completeRecoveryInstruction = [recoveryInstruction, recoveryContinuationOption].filter(Boolean).join("\n\n");
|
|
@@ -3456,7 +3608,8 @@ function compileCommandPromptWithManifest(input, options = {}) {
|
|
|
3456
3608
|
const continuationSummary = continuationText(context);
|
|
3457
3609
|
const includeTask = mode === "cold" || !continuationSummary && asRecord(input.nativeSession).mode !== "governed_action_approval";
|
|
3458
3610
|
const wakeBodies = commentBodies(context);
|
|
3459
|
-
const
|
|
3611
|
+
const hasTaskCommentIds = Array.isArray(context.paperclipTaskMarkdownCommentIds);
|
|
3612
|
+
const commentsDuplicatedByTask = !hasTaskCommentIds && hasTask && wakeBodies.length > 0 && wakeBodies.every((body) => taskText.includes(body));
|
|
3460
3613
|
const commentsSelected = mode !== "cold" || !commentsDuplicatedByTask;
|
|
3461
3614
|
const interactionResolution = interactionResolutionText(context);
|
|
3462
3615
|
const selectedComments = commentsSelected ? readString(input.comments) ?? "" : "";
|
|
@@ -3502,11 +3655,11 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3502
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 },
|
|
3503
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 }] : [],
|
|
3504
3657
|
{ name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
|
|
3505
|
-
{ 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" },
|
|
3506
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 },
|
|
3507
3660
|
{ name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
|
|
3508
3661
|
{ name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
|
|
3509
|
-
{ 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") },
|
|
3510
3663
|
{ name: "raw_snapshot", title: "Raw Context Snapshot", priority: 0, sourceRef: `run:${input.runId ?? "unknown"}`, originalChars: jsonCharLength(context), content: "", truncationReason: "on_demand_large_object" }
|
|
3511
3664
|
];
|
|
3512
3665
|
const seenContent = /* @__PURE__ */ new Set();
|
|
@@ -3560,17 +3713,24 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3560
3713
|
const fixedChars = sections.filter((section) => section.priority === 100).map(sectionText).join("\n").length;
|
|
3561
3714
|
const manifestChars = JSON.stringify(manifest).length;
|
|
3562
3715
|
if (resolvedDependencies.required.tupleCount > 0) {
|
|
3563
|
-
throw
|
|
3716
|
+
throw promptBudgetError(
|
|
3717
|
+
"resolved_dependencies_budget_exceeded",
|
|
3564
3718
|
`Resolved dependency mandatory read tuples exceed the unified ${maxChars}-character prompt budget: tupleCount=${resolvedDependencies.required.tupleCount} promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`
|
|
3565
3719
|
);
|
|
3566
3720
|
}
|
|
3567
|
-
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
|
+
);
|
|
3568
3725
|
}
|
|
3569
3726
|
truncateSection(candidate, Math.max(0, candidate.content.length - overflow - 32));
|
|
3570
3727
|
manifest = buildManifest(mode, maxChars, sections, governedReads.provenance, 0);
|
|
3571
3728
|
}
|
|
3572
3729
|
if (prompt.length > maxChars || manifest.budget.usedChars !== prompt.length) {
|
|
3573
|
-
throw
|
|
3730
|
+
throw promptBudgetError(
|
|
3731
|
+
"prompt_budget_exceeded",
|
|
3732
|
+
`Prompt compiler could not satisfy the unified ${maxChars}-character budget`
|
|
3733
|
+
);
|
|
3574
3734
|
}
|
|
3575
3735
|
return { prompt, manifest };
|
|
3576
3736
|
}
|
|
@@ -6775,6 +6935,7 @@ var ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Map([
|
|
|
6775
6935
|
[".jpeg", "image"],
|
|
6776
6936
|
[".webp", "image"],
|
|
6777
6937
|
[".gif", "image"],
|
|
6938
|
+
[".svg", "image"],
|
|
6778
6939
|
[".mp4", "video"],
|
|
6779
6940
|
[".m4v", "video"],
|
|
6780
6941
|
[".mov", "video"],
|
|
@@ -6812,7 +6973,7 @@ function isSafeRelativePath(value) {
|
|
|
6812
6973
|
const text = String(value ?? "").trim().split(/[\\/]+/).join("/");
|
|
6813
6974
|
if (!text || text.startsWith("../") || text === ".." || text.startsWith("/")) return false;
|
|
6814
6975
|
const segments = text.split("/").filter(Boolean);
|
|
6815
|
-
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");
|
|
6816
6977
|
}
|
|
6817
6978
|
function gitStatusPath(line) {
|
|
6818
6979
|
if (line.startsWith("?? ")) return line.slice(3);
|
|
@@ -6886,8 +7047,7 @@ function scanArtifactCandidates(cwd, opts = {}) {
|
|
|
6886
7047
|
}
|
|
6887
7048
|
if (!entry.isFile()) continue;
|
|
6888
7049
|
const ext = extname(entry.name).toLowerCase();
|
|
6889
|
-
const type = ARTIFACT_EXTENSIONS.get(ext);
|
|
6890
|
-
if (!type) continue;
|
|
7050
|
+
const type = ARTIFACT_EXTENSIONS.get(ext) ?? "file";
|
|
6891
7051
|
let stat;
|
|
6892
7052
|
try {
|
|
6893
7053
|
stat = statSync6(fullPath);
|
|
@@ -8744,11 +8904,10 @@ function createPublicNetworkScope(options = {}) {
|
|
|
8744
8904
|
}
|
|
8745
8905
|
|
|
8746
8906
|
// src/amaster-runtime-daemon.mjs
|
|
8747
|
-
var CONNECTOR_VERSION = "0.1.0-beta.
|
|
8907
|
+
var CONNECTOR_VERSION = "0.1.0-beta.54";
|
|
8748
8908
|
var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
|
|
8749
8909
|
var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
|
|
8750
8910
|
var CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8751
|
-
var PROMPT_AGENT_INSTRUCTION_FILE_ORDER = ["AGENTS.md", "SOUL.md"];
|
|
8752
8911
|
var AMASTER_PI_PROHIBITED_EXTRA_ARGS = /* @__PURE__ */ new Set(["--no-extensions", "--no-skills", "--no-tools", "--no-session"]);
|
|
8753
8912
|
var MAX_PI_CAPABILITY_SOURCE_ENTRIES = 200;
|
|
8754
8913
|
var PI_COMPLETION_OUTPUT_GRACE_MS = 1e3;
|
|
@@ -9869,51 +10028,46 @@ function renderIssueLine(context) {
|
|
|
9869
10028
|
const title = readString(issue.title);
|
|
9870
10029
|
return [identifier, title].filter(Boolean).join(" ");
|
|
9871
10030
|
}
|
|
9872
|
-
function renderComments(context) {
|
|
10031
|
+
function renderComments(context, options = {}) {
|
|
9873
10032
|
const wake = asRecord(context.paperclipWake);
|
|
9874
10033
|
const comments = Array.isArray(wake.comments) ? wake.comments : [];
|
|
10034
|
+
const issueId = readString(options.issueId) ?? "";
|
|
10035
|
+
let truncatedCount = 0;
|
|
9875
10036
|
const rendered = comments.map((entry, index) => {
|
|
9876
10037
|
const comment = asRecord(entry);
|
|
9877
10038
|
const id = readString(comment.id) ?? `comment-${index + 1}`;
|
|
9878
10039
|
const body = readString(comment.body) ?? "";
|
|
9879
|
-
const
|
|
9880
|
-
|
|
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}]` : "";
|
|
9881
10044
|
return `${index + 1}. ${id}
|
|
9882
10045
|
${body}${truncatedNote}`;
|
|
9883
10046
|
}).filter((entry) => entry.trim().length > 0).join("\n\n");
|
|
9884
|
-
const
|
|
9885
|
-
|
|
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");
|
|
9886
10059
|
}
|
|
9887
10060
|
function renderTaskMarkdown(context) {
|
|
9888
10061
|
return readString(context.paperclipTaskMarkdown);
|
|
9889
10062
|
}
|
|
9890
|
-
function normalizeAgentInstructionsFiles(bundle) {
|
|
9891
|
-
const files = asRecord(bundle.files);
|
|
9892
|
-
const selected = [];
|
|
9893
|
-
const seen = /* @__PURE__ */ new Set();
|
|
9894
|
-
for (const path of PROMPT_AGENT_INSTRUCTION_FILE_ORDER) {
|
|
9895
|
-
const content = readString(files[path]);
|
|
9896
|
-
if (!content) continue;
|
|
9897
|
-
selected.push({ path, content });
|
|
9898
|
-
seen.add(path);
|
|
9899
|
-
}
|
|
9900
|
-
const entryFile = readString(bundle.entryFile);
|
|
9901
|
-
if (entryFile && !seen.has(entryFile)) {
|
|
9902
|
-
const content = readString(files[entryFile]);
|
|
9903
|
-
if (content) {
|
|
9904
|
-
selected.push({ path: entryFile, content });
|
|
9905
|
-
seen.add(entryFile);
|
|
9906
|
-
}
|
|
9907
|
-
}
|
|
9908
|
-
return selected;
|
|
9909
|
-
}
|
|
9910
10063
|
function renderAgentInstructionsBundle(bundle) {
|
|
9911
|
-
const files =
|
|
9912
|
-
|
|
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 "";
|
|
9913
10067
|
return [
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
].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");
|
|
9917
10071
|
}
|
|
9918
10072
|
function commandRuntimeAuth(command) {
|
|
9919
10073
|
const topLevel = asRecord(command.runtimeAuth);
|
|
@@ -10064,13 +10218,44 @@ async function materializeAgentInstructionsBundle(config, command, workspace) {
|
|
|
10064
10218
|
}
|
|
10065
10219
|
return materialized;
|
|
10066
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
|
+
}
|
|
10067
10241
|
function buildCommandPrompt(command, workspace, materializedAttachments = [], options = {}) {
|
|
10068
10242
|
const workspaceContext = normalizeWorkspaceContext(workspace);
|
|
10069
10243
|
const cwd = workspaceContext.cwd;
|
|
10070
10244
|
const payload = asRecord(command.payload);
|
|
10071
10245
|
const context = asRecord(payload.contextSnapshot);
|
|
10072
10246
|
const issueLine = renderIssueLine(context);
|
|
10073
|
-
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
|
+
);
|
|
10074
10259
|
const taskMarkdown = renderTaskMarkdown(context);
|
|
10075
10260
|
const agentInstructions = renderAgentInstructionsBundle(asRecord(payload.agentInstructionsBundle));
|
|
10076
10261
|
const runtimeAuth = commandRuntimeAuth(command);
|
|
@@ -10110,7 +10295,11 @@ function buildCommandPrompt(command, workspace, materializedAttachments = [], op
|
|
|
10110
10295
|
attachmentsText,
|
|
10111
10296
|
comments,
|
|
10112
10297
|
context,
|
|
10113
|
-
nativeSession: asRecord(payload.nativeSession)
|
|
10298
|
+
nativeSession: asRecord(payload.nativeSession),
|
|
10299
|
+
wikiAccess: {
|
|
10300
|
+
tools: context.wikiToolsAvailable === true,
|
|
10301
|
+
treePath: wikiTreePathForCommand(command, options.workspaceBindings)
|
|
10302
|
+
}
|
|
10114
10303
|
});
|
|
10115
10304
|
}
|
|
10116
10305
|
function companyPiHomeRoot(baseEnv) {
|
|
@@ -12858,7 +13047,8 @@ async function executeRunCommand(config, command) {
|
|
|
12858
13047
|
const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
|
|
12859
13048
|
executorKind: executor.kind,
|
|
12860
13049
|
managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? MANAGED_PI_MCP_TOOL_MODE : null,
|
|
12861
|
-
artifactVerifierCommands: config.artifactVerifierCommands
|
|
13050
|
+
artifactVerifierCommands: config.artifactVerifierCommands,
|
|
13051
|
+
workspaceBindings: config.workspaceBindings
|
|
12862
13052
|
});
|
|
12863
13053
|
const nativeSessionRequest = asRecord(asRecord(command.payload).nativeSession);
|
|
12864
13054
|
const prompt = promptCompilation.prompt;
|
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",
|