@amaster.ai/employee-runtime-connector 0.1.0-beta.15 → 0.1.0-beta.16
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 +170 -14
- package/dist/amaster-runtime.mjs +1 -1
- package/package.json +1 -1
|
@@ -286,6 +286,7 @@ function parseCodexJsonl(stdout) {
|
|
|
286
286
|
let sessionId = null;
|
|
287
287
|
let summary = "";
|
|
288
288
|
let errorMessage = null;
|
|
289
|
+
let terminalEvent = null;
|
|
289
290
|
const usage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
|
|
290
291
|
|
|
291
292
|
for (const rawLine of String(stdout ?? "").split(/\r?\n/)) {
|
|
@@ -303,6 +304,7 @@ function parseCodexJsonl(stdout) {
|
|
|
303
304
|
continue;
|
|
304
305
|
}
|
|
305
306
|
if (event.type === "turn.completed") {
|
|
307
|
+
terminalEvent = "completed";
|
|
306
308
|
const eventUsage = asRecord(event.usage);
|
|
307
309
|
usage.inputTokens = readNumber(eventUsage.input_tokens, usage.inputTokens);
|
|
308
310
|
usage.cachedInputTokens = readNumber(eventUsage.cached_input_tokens, usage.cachedInputTokens);
|
|
@@ -314,12 +316,13 @@ function parseCodexJsonl(stdout) {
|
|
|
314
316
|
continue;
|
|
315
317
|
}
|
|
316
318
|
if (event.type === "turn.failed") {
|
|
319
|
+
terminalEvent = "failed";
|
|
317
320
|
const error = asRecord(event.error);
|
|
318
321
|
errorMessage = readString(error.message) ?? errorMessage;
|
|
319
322
|
}
|
|
320
323
|
}
|
|
321
324
|
|
|
322
|
-
return { sessionId, summary, usage, errorMessage };
|
|
325
|
+
return { sessionId, summary, usage, errorMessage: terminalEvent === "completed" ? null : errorMessage };
|
|
323
326
|
}
|
|
324
327
|
|
|
325
328
|
function buildCodexErrorHaystack(input) {
|
|
@@ -1653,6 +1656,26 @@ function shouldPreserveExecutorJsonlForTranscript(executorKind, event) {
|
|
|
1653
1656
|
return false;
|
|
1654
1657
|
}
|
|
1655
1658
|
|
|
1659
|
+
// ---- bundled module: src/amaster-runtime-daemon/utf8-stream-decoder.mjs ----
|
|
1660
|
+
function createUtf8StreamDecoder(onText) {
|
|
1661
|
+
const decoder = new StringDecoder("utf8");
|
|
1662
|
+
let ended = false;
|
|
1663
|
+
|
|
1664
|
+
return {
|
|
1665
|
+
write(chunk) {
|
|
1666
|
+
if (ended) throw new Error("UTF-8 stream decoder received data after end");
|
|
1667
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1668
|
+
onText(decoder.write(buffer), buffer.length);
|
|
1669
|
+
},
|
|
1670
|
+
end() {
|
|
1671
|
+
if (ended) return;
|
|
1672
|
+
ended = true;
|
|
1673
|
+
const trailingText = decoder.end();
|
|
1674
|
+
if (trailingText) onText(trailingText, 0);
|
|
1675
|
+
},
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1656
1679
|
// ---- bundled module: src/amaster-runtime-daemon/version-drift.mjs ----
|
|
1657
1680
|
function normalizeRuntimeVersionText(value) {
|
|
1658
1681
|
if (typeof value !== "string") return null;
|
|
@@ -2335,7 +2358,8 @@ import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync
|
|
|
2335
2358
|
import { homedir, hostname } from "node:os";
|
|
2336
2359
|
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
2337
2360
|
import { spawn, spawnSync } from "node:child_process";
|
|
2338
|
-
|
|
2361
|
+
import { StringDecoder } from "node:string_decoder";
|
|
2362
|
+
const CONNECTOR_VERSION = "0.1.0-beta.16";
|
|
2339
2363
|
const MAX_INFERRED_ARTIFACT_UPLOADS = 20;
|
|
2340
2364
|
const MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
|
|
2341
2365
|
const CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -3565,7 +3589,7 @@ function runtimeActionsInstruction(options = {}) {
|
|
|
3565
3589
|
"Every request_confirmation and request_checkbox_confirmation should bind the concrete decision to payload.target using {type:\"custom\", key, label, revisionId} or the applicable issue_document target. Keep target.key stable for the same decision purpose and change target.revisionId only when the target content changes. Replace example target values with task-specific values. For a custom target with no business revision, use the current run id as revisionId. For an existing issue_document target, use only the exact current revision from task context and never invent a revision id. When the same runtime action batch first upserts the target issue document, omit target.revisionId; the connector binds the created revision before posting the confirmation.",
|
|
3566
3590
|
"If the wake reason is issue_children_completed, treat the completed child tasks as already resolved blockers. Do not recreate blocker child tasks, do not repeat the first-run blocker plan, and do not create another review path unless new human input is truly required. Summarize the completed child work and use update_parent status done when no human review is needed.",
|
|
3567
3591
|
"Use update_parent status done when no human review is needed. Prefer creating a pending review path such as request_confirmation, request_checkbox_confirmation, ask_user_questions, or suggest_tasks before status in_review; if a bare in_review update is emitted, AMaster will create a fallback request_confirmation before PATCH.",
|
|
3568
|
-
"For create_child_task,
|
|
3592
|
+
"For create_child_task, set a stable workKey for the business work, plus parentDependency required or informational. Do not create ownerless executable todo tasks. Set assigneeAgentId only when the target agent id came from the current AMaster task context or an agent_hire action in this same batch. Do not invent agent ids, role ids, or ids from another company. If you are unsure, omit assigneeAgentId and assigneeUserId; AMaster will assign the current executing agent for todo/in_progress children. An ownerless backlog child must set ownerDisposition intentionally_unassigned and ownerReason; null owner alone is not an auditable disposition.",
|
|
3569
3593
|
"Create a child only for an independently executable residual work item. Do not create a nested child merely to prove that child creation works, and do not treat the current issue title as an instruction to recreate the issue itself. If the current child already embodies the requested test or work item, complete it directly.",
|
|
3570
3594
|
"Every root create_child_task with status todo or in_progress must establish the parent disposition in the same batch. Set blockParentUntilDone true when the parent depends on that child. Only omit the wait when the same batch also closes the parent's independent scope with update_parent status done or cancelled. parentId alone is structural and never proves that the parent is waiting; missing both paths fails with delegated_parent_wait_required.",
|
|
3571
3595
|
"Creating child tasks and delegating them to existing agents is task execution, not organization orchestration. Use assignee ids only from the current task context; server permissions still decide whether an assignment is allowed.",
|
|
@@ -3607,7 +3631,7 @@ function runtimeActionsInstruction(options = {}) {
|
|
|
3607
3631
|
"For create_interaction ask_user_questions, use continuationPolicy wake_assignee, never wake_assignee_on_accept, because answering questions does not produce accepted status. Every question requires 1-10 options; do not emit an open-text question without options. The UI provides an Other text answer alongside the declared options. Use payload {\"version\":1,\"title\":\"...\",\"questions\":[{\"id\":\"question_key\",\"prompt\":\"Question text\",\"selectionMode\":\"single\",\"required\":true,\"options\":[{\"id\":\"option_key\",\"label\":\"Option label\"}]}]}. Do not use question/options.value at the top level.",
|
|
3608
3632
|
"For create_interaction request_confirmation, follow the complete example above and do not use options arrays.",
|
|
3609
3633
|
"For create_interaction request_checkbox_confirmation, use payload {\"version\":1,\"prompt\":\"Select approved items\",\"options\":[{\"id\":\"option_key\",\"label\":\"Option label\"}],\"minSelected\":1,\"maxSelected\":2,\"acceptLabel\":\"确认\",\"rejectLabel\":\"调整\",\"target\":{\"type\":\"custom\",\"key\":\"approved-items\",\"label\":\"待批准项目\",\"revisionId\":\"v1\"}}.",
|
|
3610
|
-
"For create_interaction suggest_tasks, use payload {\"version\":1,\"tasks\":[{\"clientKey\":\"task_key\",\"title\":\"Task title\",\"description\":\"Task description\",\"priority\":\"medium\"}]}.",
|
|
3634
|
+
"For create_interaction suggest_tasks, use payload {\"version\":1,\"tasks\":[{\"clientKey\":\"task_key\",\"workKey\":\"stable_business_work_key\",\"title\":\"Task title\",\"description\":\"Task description\",\"priority\":\"medium\",\"ownerDisposition\":\"intentionally_unassigned\",\"ownerReason\":\"Why no owner is selected yet\",\"parentDependency\":\"informational\"}]}. Use ownerDisposition assigned_agent/assigned_user with the matching assignee id for required parent dependencies, or intentionally_unassigned with ownerReason only for informational work. parentDependency required creates a first-class parent blocker when accepted; informational does not.",
|
|
3611
3635
|
"When a suggested task should start automatically after acceptance, set assigneeAgentId to an agent id from the current task context. Set assigneeUserId only when a known user must own the task. Omit both assignee fields only when the accepted task should remain intentionally unassigned in backlog. Never substitute a role name for an assignee id.",
|
|
3612
3636
|
"An external input or human approval cannot exist only as free-text owner/next-step prose. Create a human-owned create_child_task with assigneeUserId and blockParentUntilDone=true (or another explicit interaction/dependency path), then keep the parent blocked or in_review until it resolves.",
|
|
3613
3637
|
"Do not copy placeholder names, placeholder summaries, placeholder action arrays, or placeholder paths. Every title, body, role, idempotencyKey, artifact path, and task description must be specific to the current issue and company.",
|
|
@@ -4865,6 +4889,8 @@ function runExecutor(command, args, options) {
|
|
|
4865
4889
|
let stoppedExitDrainTimer = null;
|
|
4866
4890
|
let completionOutputDrainTimer = null;
|
|
4867
4891
|
let piCompletionOutputLineBuffer = "";
|
|
4892
|
+
let stdoutDecoder = null;
|
|
4893
|
+
let stderrDecoder = null;
|
|
4868
4894
|
const outputBytes = { stdout: 0, stderr: 0 };
|
|
4869
4895
|
const maxOutputBytes = parsePositiveInteger(options.maxOutputBytes, 50 * 1024 * 1024);
|
|
4870
4896
|
const maxRssMb = parsePositiveInteger(options.maxRssMb, 0);
|
|
@@ -4879,6 +4905,8 @@ function runExecutor(command, args, options) {
|
|
|
4879
4905
|
const finish = (result) => {
|
|
4880
4906
|
if (settled) return;
|
|
4881
4907
|
settled = true;
|
|
4908
|
+
stdoutDecoder?.end();
|
|
4909
|
+
stderrDecoder?.end();
|
|
4882
4910
|
if (timer) clearTimeout(timer);
|
|
4883
4911
|
if (rssTimer) clearInterval(rssTimer);
|
|
4884
4912
|
if (stopKillTimer) clearTimeout(stopKillTimer);
|
|
@@ -5001,21 +5029,25 @@ function runExecutor(command, args, options) {
|
|
|
5001
5029
|
}, 1000);
|
|
5002
5030
|
rssTimer.unref?.();
|
|
5003
5031
|
}
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
outputBytes.stdout += chunk.length;
|
|
5032
|
+
stdoutDecoder = createUtf8StreamDecoder((text, byteLength) => {
|
|
5033
|
+
outputBytes.stdout += byteLength;
|
|
5007
5034
|
stdout = appendBounded(stdout, text);
|
|
5008
|
-
options.onOutput?.("stdout", text,
|
|
5035
|
+
options.onOutput?.("stdout", text, byteLength);
|
|
5009
5036
|
maybeSchedulePiCompletionDrain(text);
|
|
5010
5037
|
if (outputBytes.stdout > maxOutputBytes) killForOutputFlood("stdout");
|
|
5011
5038
|
});
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
outputBytes.stderr += chunk.length;
|
|
5039
|
+
stderrDecoder = createUtf8StreamDecoder((text, byteLength) => {
|
|
5040
|
+
outputBytes.stderr += byteLength;
|
|
5015
5041
|
stderr = appendBounded(stderr, text);
|
|
5016
|
-
options.onOutput?.("stderr", text,
|
|
5042
|
+
options.onOutput?.("stderr", text, byteLength);
|
|
5017
5043
|
if (outputBytes.stderr > maxOutputBytes) killForOutputFlood("stderr");
|
|
5018
5044
|
});
|
|
5045
|
+
child.stdout.on("data", (chunk) => {
|
|
5046
|
+
if (!settled) stdoutDecoder.write(chunk);
|
|
5047
|
+
});
|
|
5048
|
+
child.stderr.on("data", (chunk) => {
|
|
5049
|
+
if (!settled) stderrDecoder.write(chunk);
|
|
5050
|
+
});
|
|
5019
5051
|
child.on("error", (err) => {
|
|
5020
5052
|
finish({ exitCode: null, signal: null, timedOut: false, spawnError: err.message });
|
|
5021
5053
|
});
|
|
@@ -6326,6 +6358,8 @@ function hashFileSha256(filePath) {
|
|
|
6326
6358
|
}
|
|
6327
6359
|
|
|
6328
6360
|
function runtimeChildActionFingerprint(action, issueId, parentIssueId) {
|
|
6361
|
+
const workKey = readString(action.workKey);
|
|
6362
|
+
if (workKey) return `amaster-work:${workKey}`;
|
|
6329
6363
|
const explicit = readString(action.idempotencyKey);
|
|
6330
6364
|
if (explicit) return explicit.slice(0, 220);
|
|
6331
6365
|
const clientKey = readString(action.clientKey) ?? readString(action.key);
|
|
@@ -6916,10 +6950,14 @@ function normalizeRuntimeSuggestedTask(task, index) {
|
|
|
6916
6950
|
const priority = normalizeRuntimeActionPriority(record.priority);
|
|
6917
6951
|
return {
|
|
6918
6952
|
clientKey: runtimeInteractionOptionId(record.clientKey ?? record.key ?? title, fallbackClientKey),
|
|
6953
|
+
...(readString(record.workKey) ? { workKey: readString(record.workKey) } : {}),
|
|
6919
6954
|
title: title.slice(0, 240),
|
|
6920
6955
|
...(readString(record.description) ? { description: readString(record.description) } : {}),
|
|
6921
6956
|
...(readString(record.assigneeAgentId) ? { assigneeAgentId: readString(record.assigneeAgentId) } : {}),
|
|
6922
6957
|
...(readString(record.assigneeUserId) ? { assigneeUserId: readString(record.assigneeUserId) } : {}),
|
|
6958
|
+
...(readString(record.ownerDisposition) ? { ownerDisposition: readString(record.ownerDisposition) } : {}),
|
|
6959
|
+
...(readString(record.ownerReason) ? { ownerReason: readString(record.ownerReason) } : {}),
|
|
6960
|
+
...(readString(record.parentDependency) ? { parentDependency: readString(record.parentDependency) } : {}),
|
|
6923
6961
|
...(readString(record.projectId) ? { projectId: readString(record.projectId) } : {}),
|
|
6924
6962
|
...(readString(record.parentId) ? { parentId: readString(record.parentId) } : {}),
|
|
6925
6963
|
...(priority ? { priority } : {}),
|
|
@@ -7230,7 +7268,7 @@ const RUNTIME_ACTION_ALLOWED_FIELDS = new Map([
|
|
|
7230
7268
|
"title", "description", "status", "priority", "assigneeAgentId", "assigneeUserId",
|
|
7231
7269
|
"assigneeAgentClientKey", "agentClientKey", "blockParentUntilDone", "executeBeforeConfirmation",
|
|
7232
7270
|
"clientKey", "idempotencyKey", "parentClientKey", "blockedByIssueIds", "blockedByClientKeys", "create_child_task",
|
|
7233
|
-
"inputWorkProductIds",
|
|
7271
|
+
"inputWorkProductIds", "workKey", "ownerDisposition", "ownerReason", "parentDependency",
|
|
7234
7272
|
])],
|
|
7235
7273
|
["agent_hire", new Set([
|
|
7236
7274
|
"clientKey", "idempotencyKey", "key", "companyId", "role", "title", "icon", "reportsTo",
|
|
@@ -7514,11 +7552,42 @@ function assertRuntimeCreateInteractionPayload(kind, payload) {
|
|
|
7514
7552
|
for (const [index, rawTask] of tasks.entries()) {
|
|
7515
7553
|
const task = asRecord(rawTask);
|
|
7516
7554
|
const clientKey = readString(task.clientKey);
|
|
7555
|
+
const workKey = readString(task.workKey);
|
|
7517
7556
|
const title = readString(task.title);
|
|
7518
7557
|
assertRuntimeActionValid(clientKey && clientKey.length <= 120, `suggest_tasks payload tasks[${index}].clientKey is required`);
|
|
7519
7558
|
assertRuntimeActionValid(!clientKeys.has(clientKey), `suggest_tasks payload tasks[${index}].clientKey must be unique`);
|
|
7520
7559
|
clientKeys.add(clientKey);
|
|
7560
|
+
assertRuntimeActionValid(workKey && workKey.length <= 120, `suggest_tasks payload tasks[${index}].workKey is required`);
|
|
7521
7561
|
assertRuntimeActionValid(title && title.length <= 240, `suggest_tasks payload tasks[${index}].title is required`);
|
|
7562
|
+
const ownerDisposition = readString(task.ownerDisposition);
|
|
7563
|
+
const assigneeAgentId = readString(task.assigneeAgentId);
|
|
7564
|
+
const assigneeUserId = readString(task.assigneeUserId);
|
|
7565
|
+
assertRuntimeActionValid(
|
|
7566
|
+
["assigned_agent", "assigned_user", "intentionally_unassigned"].includes(ownerDisposition ?? ""),
|
|
7567
|
+
`suggest_tasks payload tasks[${index}].ownerDisposition is required`,
|
|
7568
|
+
);
|
|
7569
|
+
assertRuntimeActionValid(
|
|
7570
|
+
ownerDisposition !== "assigned_agent" || Boolean(assigneeAgentId),
|
|
7571
|
+
`suggest_tasks payload tasks[${index}] assigned_agent requires assigneeAgentId`,
|
|
7572
|
+
);
|
|
7573
|
+
assertRuntimeActionValid(
|
|
7574
|
+
ownerDisposition !== "assigned_user" || Boolean(assigneeUserId),
|
|
7575
|
+
`suggest_tasks payload tasks[${index}] assigned_user requires assigneeUserId`,
|
|
7576
|
+
);
|
|
7577
|
+
assertRuntimeActionValid(
|
|
7578
|
+
ownerDisposition !== "intentionally_unassigned"
|
|
7579
|
+
|| (!assigneeAgentId && !assigneeUserId && Boolean(readString(task.ownerReason))),
|
|
7580
|
+
`suggest_tasks payload tasks[${index}] intentionally_unassigned requires ownerReason and forbids assignee ids`,
|
|
7581
|
+
);
|
|
7582
|
+
const parentDependency = readString(task.parentDependency);
|
|
7583
|
+
assertRuntimeActionValid(
|
|
7584
|
+
["required", "informational"].includes(parentDependency ?? ""),
|
|
7585
|
+
`suggest_tasks payload tasks[${index}].parentDependency is required`,
|
|
7586
|
+
);
|
|
7587
|
+
assertRuntimeActionValid(
|
|
7588
|
+
ownerDisposition !== "intentionally_unassigned" || parentDependency !== "required",
|
|
7589
|
+
"intentionally_unassigned work cannot be a required parent dependency",
|
|
7590
|
+
);
|
|
7522
7591
|
}
|
|
7523
7592
|
}
|
|
7524
7593
|
}
|
|
@@ -7705,12 +7774,59 @@ function preflightRuntimeAction(action, preflightContext, actionIndex) {
|
|
|
7705
7774
|
if (type === "create_child_task") {
|
|
7706
7775
|
assertNoPlaceholderRuntimeActionText(fields, ["title", "description"]);
|
|
7707
7776
|
assertRuntimeActionValid(readBoundedActionString(fields, "title", 240), "create_child_task action requires title");
|
|
7777
|
+
if (fields.workKey !== undefined) {
|
|
7778
|
+
assertRuntimeActionValid(Boolean(readString(fields.workKey)), "create_child_task workKey must be a non-empty string");
|
|
7779
|
+
}
|
|
7708
7780
|
if (fields.status !== undefined) {
|
|
7709
7781
|
assertRuntimeActionValid(readActionStatus(fields.status), `create_child_task status is unsupported: ${String(fields.status)}`);
|
|
7710
7782
|
}
|
|
7711
7783
|
if (fields.priority !== undefined) {
|
|
7712
7784
|
assertRuntimeActionValid(readActionPriority(fields.priority), `create_child_task priority is unsupported: ${String(fields.priority)}`);
|
|
7713
7785
|
}
|
|
7786
|
+
const childStatus = readActionStatus(fields.status) ?? "todo";
|
|
7787
|
+
if (fields.parentDependency !== undefined) {
|
|
7788
|
+
assertRuntimeActionValid(
|
|
7789
|
+
["required", "informational"].includes(readString(fields.parentDependency) ?? ""),
|
|
7790
|
+
"create_child_task parentDependency must be required or informational",
|
|
7791
|
+
);
|
|
7792
|
+
assertRuntimeActionValid(
|
|
7793
|
+
(readString(fields.parentDependency) === "required") === (fields.blockParentUntilDone === true || childStatus === "blocked"),
|
|
7794
|
+
"create_child_task parentDependency must match blockParentUntilDone",
|
|
7795
|
+
);
|
|
7796
|
+
}
|
|
7797
|
+
const ownerDisposition = readString(fields.ownerDisposition);
|
|
7798
|
+
if (ownerDisposition) {
|
|
7799
|
+
assertRuntimeActionValid(
|
|
7800
|
+
["assigned_agent", "assigned_user", "intentionally_unassigned"].includes(ownerDisposition),
|
|
7801
|
+
"create_child_task ownerDisposition is unsupported",
|
|
7802
|
+
);
|
|
7803
|
+
}
|
|
7804
|
+
if (
|
|
7805
|
+
childStatus === "backlog"
|
|
7806
|
+
&& !readString(fields.assigneeAgentId)
|
|
7807
|
+
&& !readString(fields.assigneeUserId)
|
|
7808
|
+
&& !readString(fields.assigneeAgentClientKey)
|
|
7809
|
+
&& !readString(fields.agentClientKey)
|
|
7810
|
+
) {
|
|
7811
|
+
assertRuntimeActionValid(
|
|
7812
|
+
ownerDisposition === "intentionally_unassigned" && Boolean(readString(fields.ownerReason)),
|
|
7813
|
+
"ownerless backlog create_child_task requires ownerDisposition intentionally_unassigned and ownerReason",
|
|
7814
|
+
);
|
|
7815
|
+
}
|
|
7816
|
+
if (ownerDisposition === "intentionally_unassigned") {
|
|
7817
|
+
assertRuntimeActionValid(
|
|
7818
|
+
!readString(fields.assigneeAgentId)
|
|
7819
|
+
&& !readString(fields.assigneeUserId)
|
|
7820
|
+
&& !readString(fields.assigneeAgentClientKey)
|
|
7821
|
+
&& !readString(fields.agentClientKey)
|
|
7822
|
+
&& Boolean(readString(fields.ownerReason)),
|
|
7823
|
+
"create_child_task intentionally_unassigned requires ownerReason and forbids assignee fields",
|
|
7824
|
+
);
|
|
7825
|
+
assertRuntimeActionValid(
|
|
7826
|
+
readString(fields.parentDependency) !== "required",
|
|
7827
|
+
"intentionally_unassigned work cannot be a required parent dependency",
|
|
7828
|
+
);
|
|
7829
|
+
}
|
|
7714
7830
|
assertRuntimeActionValid(
|
|
7715
7831
|
!readString(fields.assigneeAgentId) || (!readString(fields.assigneeAgentClientKey) && !readString(fields.agentClientKey)),
|
|
7716
7832
|
"create_child_task action cannot combine assigneeAgentId with assigneeAgentClientKey/agentClientKey",
|
|
@@ -7915,6 +8031,41 @@ function preflightRuntimeActionBatch(actions, options = {}) {
|
|
|
7915
8031
|
assertDelegatedParentWaitDisposition(actions);
|
|
7916
8032
|
const orderedActions = orderRuntimeActionsByClientKeyDependencies(actions);
|
|
7917
8033
|
const documentActionIndexByKey = new Map();
|
|
8034
|
+
const workKeyOwner = new Map();
|
|
8035
|
+
const hasSuggestedTaskProposal = orderedActions.some((action) => {
|
|
8036
|
+
const fields = runtimeActionBusinessFields(action);
|
|
8037
|
+
return readRuntimeActionType(fields) === "create_interaction" && inferCreateInteractionKind(fields) === "suggest_tasks";
|
|
8038
|
+
});
|
|
8039
|
+
for (const action of orderedActions) {
|
|
8040
|
+
const fields = runtimeActionBusinessFields(action);
|
|
8041
|
+
const actionIndex = actionIndexByObject.get(action);
|
|
8042
|
+
if (hasSuggestedTaskProposal && readRuntimeActionType(fields) === "create_child_task") {
|
|
8043
|
+
assertRuntimeActionValid(
|
|
8044
|
+
Boolean(readString(fields.workKey)),
|
|
8045
|
+
"create_child_task action requires workKey when the same batch also proposes suggest_tasks",
|
|
8046
|
+
);
|
|
8047
|
+
}
|
|
8048
|
+
const entries = readRuntimeActionType(fields) === "create_child_task"
|
|
8049
|
+
? [{ workKey: readString(fields.workKey), fieldPath: `actions[${actionIndex}].workKey` }]
|
|
8050
|
+
: readRuntimeActionType(fields) === "create_interaction" && inferCreateInteractionKind(fields) === "suggest_tasks"
|
|
8051
|
+
? (Array.isArray(asRecord(fields.payload).tasks) ? asRecord(fields.payload).tasks : []).map((task, taskIndex) => ({
|
|
8052
|
+
workKey: readString(asRecord(task).workKey),
|
|
8053
|
+
fieldPath: `actions[${actionIndex}].payload.tasks[${taskIndex}].workKey`,
|
|
8054
|
+
}))
|
|
8055
|
+
: [];
|
|
8056
|
+
for (const entry of entries) {
|
|
8057
|
+
if (!entry.workKey) continue;
|
|
8058
|
+
const priorPath = workKeyOwner.get(entry.workKey);
|
|
8059
|
+
if (priorPath) {
|
|
8060
|
+
const err = runtimeActionValidationError(
|
|
8061
|
+
`workKey ${entry.workKey} appears more than once in the runtime action batch (${priorPath}, ${entry.fieldPath})`,
|
|
8062
|
+
);
|
|
8063
|
+
err.runtimeActionFieldPath = entry.fieldPath;
|
|
8064
|
+
throw err;
|
|
8065
|
+
}
|
|
8066
|
+
workKeyOwner.set(entry.workKey, entry.fieldPath);
|
|
8067
|
+
}
|
|
8068
|
+
}
|
|
7918
8069
|
for (const action of orderedActions) {
|
|
7919
8070
|
if (readRuntimeActionType(action) !== "upsert_document") continue;
|
|
7920
8071
|
const key = readBoundedActionString(runtimeActionBusinessFields(action), "key", 64);
|
|
@@ -8227,7 +8378,7 @@ async function applyRuntimeAction(config, command, runtimeAuth, issueId, action,
|
|
|
8227
8378
|
? { inputWorkProductIds: fields.inputWorkProductIds.map(readString).filter(Boolean) }
|
|
8228
8379
|
: {}),
|
|
8229
8380
|
blockParentUntilDone,
|
|
8230
|
-
originKind: "amaster_runtime_child_task",
|
|
8381
|
+
originKind: readString(fields.workKey) ? "amaster_runtime_work" : "amaster_runtime_child_task",
|
|
8231
8382
|
originId: issueId,
|
|
8232
8383
|
originRunId: runId,
|
|
8233
8384
|
originFingerprint,
|
|
@@ -9474,6 +9625,11 @@ function assertRuntimeMarkdownSourceTruth(sourceTruthValue, fieldPath, filePath)
|
|
|
9474
9625
|
const allowedFields = new Set(["status", "reason", "sources", "unverifiedClaims"]);
|
|
9475
9626
|
for (const field of Object.keys(sourceTruth)) {
|
|
9476
9627
|
if (!allowedFields.has(field)) {
|
|
9628
|
+
if (field === "assumptions") {
|
|
9629
|
+
throw runtimeDeliverableError(
|
|
9630
|
+
`${fieldPath}.assumptions is unsupported; use ${fieldPath}.unverifiedClaims instead`,
|
|
9631
|
+
);
|
|
9632
|
+
}
|
|
9477
9633
|
throw runtimeDeliverableError(`${fieldPath}.${field} is unsupported`);
|
|
9478
9634
|
}
|
|
9479
9635
|
}
|
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.16";
|
|
9
9
|
|
|
10
10
|
const CAPABILITIES = [
|
|
11
11
|
"remote_registration",
|