@amaster.ai/employee-runtime-connector 0.1.0-beta.12 → 0.1.0-beta.13
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 +110 -11
- package/dist/amaster-runtime.mjs +1 -1
- package/package.json +1 -1
|
@@ -2335,7 +2335,7 @@ import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync
|
|
|
2335
2335
|
import { homedir, hostname } from "node:os";
|
|
2336
2336
|
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
2337
2337
|
import { spawn, spawnSync } from "node:child_process";
|
|
2338
|
-
const CONNECTOR_VERSION = "0.1.0-beta.
|
|
2338
|
+
const CONNECTOR_VERSION = "0.1.0-beta.13";
|
|
2339
2339
|
const MAX_INFERRED_ARTIFACT_UPLOADS = 20;
|
|
2340
2340
|
const MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
|
|
2341
2341
|
const CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -3562,7 +3562,7 @@ function runtimeActionsInstruction(options = {}) {
|
|
|
3562
3562
|
"If direct AMaster API requests are unavailable from the executor sandbox, do not stop at blocked. Use the runtime action bridge for the unapplied mutations.",
|
|
3563
3563
|
"Use runtime actions as a continuation patch, not as a full replay. If the wake reason or latest comments say a confirmation was accepted, rejected, or that no more child tasks/interactions should be created, do not recreate those earlier actions. Add the final result comment and update the parent task instead.",
|
|
3564
3564
|
"On an accepted request_confirmation or request_checkbox_confirmation continuation, any new confirmation must include payload.target.type and a non-empty payload.target.key. Missing decision identity fields fail before mutation with accepted_confirmation_decision_target_required. The server reuses identical content for the same target identity and rejects changed prompt, options, or labels until the action uses the genuinely new target revision.",
|
|
3565
|
-
"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
|
|
3565
|
+
"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
3566
|
"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
3567
|
"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
3568
|
"For create_child_task, 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. Use backlog only when a task is intentionally unassigned.",
|
|
@@ -7555,7 +7555,7 @@ function assertRuntimeConfirmationTarget(target) {
|
|
|
7555
7555
|
key.length <= 64 && /^[a-z0-9][a-z0-9_-]*$/.test(key),
|
|
7556
7556
|
"confirmation issue_document target key must use lowercase letters, numbers, _ or -",
|
|
7557
7557
|
);
|
|
7558
|
-
assertRuntimeActionValid(revisionId
|
|
7558
|
+
assertRuntimeActionValid(!revisionId || uuidPattern.test(revisionId), "confirmation issue_document target revisionId must be a UUID");
|
|
7559
7559
|
for (const field of ["issueId", "documentId"]) {
|
|
7560
7560
|
const value = readString(record[field]);
|
|
7561
7561
|
assertRuntimeActionValid(!value || uuidPattern.test(value), `confirmation issue_document target ${field} must be a UUID`);
|
|
@@ -7930,6 +7930,33 @@ function preflightRuntimeActionBatch(actions, options = {}) {
|
|
|
7930
7930
|
}
|
|
7931
7931
|
documentActionIndexByKey.set(key, actionIndex);
|
|
7932
7932
|
}
|
|
7933
|
+
for (const action of orderedActions) {
|
|
7934
|
+
const fields = runtimeActionBusinessFields(action);
|
|
7935
|
+
if (readRuntimeActionType(fields) !== "create_interaction") continue;
|
|
7936
|
+
const kind = inferCreateInteractionKind(fields);
|
|
7937
|
+
if (!["request_confirmation", "request_checkbox_confirmation"].includes(kind ?? "")) continue;
|
|
7938
|
+
const target = asRecord(asRecord(fields.payload).target);
|
|
7939
|
+
if (readString(target.type) !== "issue_document") continue;
|
|
7940
|
+
const key = readString(target.key);
|
|
7941
|
+
if (!key) continue;
|
|
7942
|
+
const actionIndex = actionIndexByObject.get(action);
|
|
7943
|
+
const sameBatchDocumentActionIndex = documentActionIndexByKey.get(key);
|
|
7944
|
+
const sameBatchDocumentUpsert = Number.isInteger(sameBatchDocumentActionIndex);
|
|
7945
|
+
const revisionId = readString(target.revisionId);
|
|
7946
|
+
if (sameBatchDocumentUpsert && !revisionId && sameBatchDocumentActionIndex < actionIndex) continue;
|
|
7947
|
+
if (!sameBatchDocumentUpsert && revisionId) continue;
|
|
7948
|
+
const err = runtimeActionValidationError(
|
|
7949
|
+
sameBatchDocumentUpsert
|
|
7950
|
+
? revisionId
|
|
7951
|
+
? `same-batch issue document confirmation for ${key} must omit revisionId so the connector can bind the created revision`
|
|
7952
|
+
: `same-batch issue document confirmation for ${key} requires an earlier upsert_document action so the connector can bind the created revision before applying the interaction`
|
|
7953
|
+
: `issue document confirmation for ${key} requires revisionId when the document is not upserted in the same batch`,
|
|
7954
|
+
);
|
|
7955
|
+
err.runtimeActionType = "create_interaction";
|
|
7956
|
+
err.runtimeActionKind = kind;
|
|
7957
|
+
err.runtimeActionFieldPath = `actions[${actionIndex}].payload.target.revisionId`;
|
|
7958
|
+
throw err;
|
|
7959
|
+
}
|
|
7933
7960
|
assertRuntimeActionsAllowedByContinuationScope(orderedActions, options.continuationScope);
|
|
7934
7961
|
assertNoAmbiguousApprovalGatedSideEffects(orderedActions);
|
|
7935
7962
|
const preflightContext = {
|
|
@@ -7983,11 +8010,9 @@ function preflightRuntimeActionBatch(actions, options = {}) {
|
|
|
7983
8010
|
|
|
7984
8011
|
async function preflightRuntimeDocumentRevisions(runtimeAuth, issueId, actions) {
|
|
7985
8012
|
const baseRevisionIdsByKey = new Map();
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
const key = readBoundedActionString(fields, "key", 64);
|
|
7990
|
-
if (!key) continue;
|
|
8013
|
+
const existingDocumentsByKey = new Map();
|
|
8014
|
+
const readExistingDocument = async (key) => {
|
|
8015
|
+
if (existingDocumentsByKey.has(key)) return existingDocumentsByKey.get(key);
|
|
7991
8016
|
let existingDocument = null;
|
|
7992
8017
|
try {
|
|
7993
8018
|
existingDocument = asRecord(await runtimeApiJson(
|
|
@@ -7998,6 +8023,15 @@ async function preflightRuntimeDocumentRevisions(runtimeAuth, issueId, actions)
|
|
|
7998
8023
|
} catch (err) {
|
|
7999
8024
|
if (err?.httpStatus !== 404) throw err;
|
|
8000
8025
|
}
|
|
8026
|
+
existingDocumentsByKey.set(key, existingDocument);
|
|
8027
|
+
return existingDocument;
|
|
8028
|
+
};
|
|
8029
|
+
for (const [actionIndex, action] of actions.entries()) {
|
|
8030
|
+
if (readRuntimeActionType(action) !== "upsert_document") continue;
|
|
8031
|
+
const fields = runtimeActionBusinessFields(action);
|
|
8032
|
+
const key = readBoundedActionString(fields, "key", 64);
|
|
8033
|
+
if (!key) continue;
|
|
8034
|
+
const existingDocument = await readExistingDocument(key);
|
|
8001
8035
|
|
|
8002
8036
|
const explicitBaseRevisionId = readString(fields.baseRevisionId);
|
|
8003
8037
|
const currentRevisionId = readString(existingDocument?.latestRevisionId);
|
|
@@ -8028,6 +8062,29 @@ async function preflightRuntimeDocumentRevisions(runtimeAuth, issueId, actions)
|
|
|
8028
8062
|
}
|
|
8029
8063
|
baseRevisionIdsByKey.set(key, currentRevisionId);
|
|
8030
8064
|
}
|
|
8065
|
+
for (const [actionIndex, action] of actions.entries()) {
|
|
8066
|
+
const fields = runtimeActionBusinessFields(action);
|
|
8067
|
+
if (readRuntimeActionType(fields) !== "create_interaction") continue;
|
|
8068
|
+
const kind = inferCreateInteractionKind(fields);
|
|
8069
|
+
if (!["request_confirmation", "request_checkbox_confirmation"].includes(kind ?? "")) continue;
|
|
8070
|
+
const target = asRecord(asRecord(fields.payload).target);
|
|
8071
|
+
if (readString(target.type) !== "issue_document") continue;
|
|
8072
|
+
const key = readString(target.key);
|
|
8073
|
+
if (!key || baseRevisionIdsByKey.has(key)) continue;
|
|
8074
|
+
const existingDocument = await readExistingDocument(key);
|
|
8075
|
+
const currentRevisionId = readString(existingDocument?.latestRevisionId);
|
|
8076
|
+
const targetRevisionId = readString(target.revisionId);
|
|
8077
|
+
if (currentRevisionId && currentRevisionId === targetRevisionId) continue;
|
|
8078
|
+
const err = runtimeActionValidationError(
|
|
8079
|
+
currentRevisionId
|
|
8080
|
+
? `issue document confirmation target ${key} is stale; current revision is ${currentRevisionId}`
|
|
8081
|
+
: `issue document confirmation target ${key} does not exist`,
|
|
8082
|
+
);
|
|
8083
|
+
err.runtimeActionType = "create_interaction";
|
|
8084
|
+
err.runtimeActionKind = kind;
|
|
8085
|
+
err.runtimeActionFieldPath = `actions[${actionIndex}].payload.target.revisionId`;
|
|
8086
|
+
throw err;
|
|
8087
|
+
}
|
|
8031
8088
|
return baseRevisionIdsByKey;
|
|
8032
8089
|
}
|
|
8033
8090
|
|
|
@@ -8434,10 +8491,23 @@ async function applyRuntimeAction(config, command, runtimeAuth, issueId, action,
|
|
|
8434
8491
|
if (!["request_confirmation", "request_checkbox_confirmation", "ask_user_questions", "suggest_tasks"].includes(kind)) {
|
|
8435
8492
|
throw new Error(`create_interaction action does not support kind: ${kind}`);
|
|
8436
8493
|
}
|
|
8437
|
-
|
|
8494
|
+
let payload = normalizeCreateInteractionPayload(fields, kind);
|
|
8438
8495
|
if (Object.keys(payload).length === 0) {
|
|
8439
8496
|
throw new Error("create_interaction action requires payload");
|
|
8440
8497
|
}
|
|
8498
|
+
const interactionTarget = asRecord(payload.target);
|
|
8499
|
+
if (
|
|
8500
|
+
["request_confirmation", "request_checkbox_confirmation"].includes(kind) &&
|
|
8501
|
+
readString(interactionTarget.type) === "issue_document" &&
|
|
8502
|
+
!readString(interactionTarget.revisionId)
|
|
8503
|
+
) {
|
|
8504
|
+
const key = readString(interactionTarget.key);
|
|
8505
|
+
const boundTarget = key ? actionContext.issueDocumentTargetsByKey.get(key) : null;
|
|
8506
|
+
if (!boundTarget) {
|
|
8507
|
+
throw new Error(`issue document confirmation target ${String(key)} was not created earlier in the runtime action batch`);
|
|
8508
|
+
}
|
|
8509
|
+
payload = { ...payload, target: boundTarget };
|
|
8510
|
+
}
|
|
8441
8511
|
const defaultContinuationPolicy = "wake_assignee";
|
|
8442
8512
|
const createBody = {
|
|
8443
8513
|
kind,
|
|
@@ -8492,13 +8562,30 @@ async function applyRuntimeAction(config, command, runtimeAuth, issueId, action,
|
|
|
8492
8562
|
?? null,
|
|
8493
8563
|
},
|
|
8494
8564
|
));
|
|
8565
|
+
const latestRevisionId = readString(document.latestRevisionId);
|
|
8566
|
+
const latestRevisionNumber = readNumber(document.latestRevisionNumber, null) ?? undefined;
|
|
8567
|
+
const documentId = readString(document.id);
|
|
8568
|
+
if (actionContext.issueDocumentConfirmationKeysNeedingBinding.has(key)) {
|
|
8569
|
+
if (!documentId || !latestRevisionId || !latestRevisionNumber) {
|
|
8570
|
+
throw new Error(`upsert_document ${key} response did not expose the created document revision`);
|
|
8571
|
+
}
|
|
8572
|
+
actionContext.issueDocumentTargetsByKey.set(key, {
|
|
8573
|
+
type: "issue_document",
|
|
8574
|
+
issueId,
|
|
8575
|
+
documentId,
|
|
8576
|
+
key,
|
|
8577
|
+
revisionId: latestRevisionId,
|
|
8578
|
+
revisionNumber: latestRevisionNumber,
|
|
8579
|
+
});
|
|
8580
|
+
}
|
|
8495
8581
|
return {
|
|
8496
8582
|
type,
|
|
8497
8583
|
...(originalType && originalType !== type ? { originalType } : {}),
|
|
8498
8584
|
issueId,
|
|
8499
8585
|
key,
|
|
8500
|
-
documentId
|
|
8501
|
-
|
|
8586
|
+
documentId,
|
|
8587
|
+
revisionId: latestRevisionId ?? undefined,
|
|
8588
|
+
revisionNumber: latestRevisionNumber,
|
|
8502
8589
|
};
|
|
8503
8590
|
}
|
|
8504
8591
|
|
|
@@ -9694,6 +9781,16 @@ async function applyRuntimeActionBridge(config, command, parsed, execution, cwd)
|
|
|
9694
9781
|
const results = [];
|
|
9695
9782
|
const skipped = [];
|
|
9696
9783
|
const actionLedgerEntries = [];
|
|
9784
|
+
const issueDocumentConfirmationKeysNeedingBinding = new Set(actions.flatMap((action) => {
|
|
9785
|
+
const fields = runtimeActionBusinessFields(action);
|
|
9786
|
+
if (readRuntimeActionType(fields) !== "create_interaction") return [];
|
|
9787
|
+
const kind = inferCreateInteractionKind(fields);
|
|
9788
|
+
if (!["request_confirmation", "request_checkbox_confirmation"].includes(kind ?? "")) return [];
|
|
9789
|
+
const target = asRecord(asRecord(fields.payload).target);
|
|
9790
|
+
if (readString(target.type) !== "issue_document" || readString(target.revisionId)) return [];
|
|
9791
|
+
const key = readString(target.key);
|
|
9792
|
+
return key ? [key] : [];
|
|
9793
|
+
}));
|
|
9697
9794
|
const actionContext = {
|
|
9698
9795
|
rootIssueId: issueId,
|
|
9699
9796
|
cwd,
|
|
@@ -9706,6 +9803,8 @@ async function applyRuntimeActionBridge(config, command, parsed, execution, cwd)
|
|
|
9706
9803
|
acceptedConfirmationContinuation,
|
|
9707
9804
|
answeredQuestionContinuation,
|
|
9708
9805
|
documentBaseRevisionIdsByKey,
|
|
9806
|
+
issueDocumentConfirmationKeysNeedingBinding,
|
|
9807
|
+
issueDocumentTargetsByKey: new Map(),
|
|
9709
9808
|
finalCommentBodies: [],
|
|
9710
9809
|
};
|
|
9711
9810
|
for (const [actionIndex, action] of actions.entries()) {
|
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.13";
|
|
9
9
|
|
|
10
10
|
const CAPABILITIES = [
|
|
11
11
|
"remote_registration",
|