@granular-software/sdk 0.4.69 → 0.4.71
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/agent-evals.d.mts +2 -2
- package/dist/agent-evals.d.ts +2 -2
- package/dist/agent-evals.js +286 -27
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +286 -27
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.js +4 -0
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +4 -0
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +282 -27
- package/dist/{client-D1gq4TO4.d.ts → client-JCISbded.d.ts} +23 -3
- package/dist/{client-qgWZ495o.d.mts → client-p5EhOwpP.d.mts} +23 -3
- package/dist/delegated-auth.d.mts +25 -0
- package/dist/delegated-auth.d.ts +25 -0
- package/dist/delegated-auth.js +352 -0
- package/dist/delegated-auth.js.map +1 -0
- package/dist/delegated-auth.mjs +350 -0
- package/dist/delegated-auth.mjs.map +1 -0
- package/dist/index.d.mts +67 -4
- package/dist/index.d.ts +67 -4
- package/dist/index.js +1396 -232
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1385 -233
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-B-IQmp7F.d.mts → spend-lJDtuAr6.d.mts} +109 -2
- package/dist/{spend-B-IQmp7F.d.ts → spend-lJDtuAr6.d.ts} +109 -2
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -4300,8 +4300,8 @@ function normalizeFeedItems(values) {
|
|
|
4300
4300
|
return { items: Object.freeze(items), error };
|
|
4301
4301
|
}
|
|
4302
4302
|
function normalizeTransients(values) {
|
|
4303
|
-
const
|
|
4304
|
-
if (!
|
|
4303
|
+
const record2 = asRecord(values);
|
|
4304
|
+
if (!record2) {
|
|
4305
4305
|
return {
|
|
4306
4306
|
items: [],
|
|
4307
4307
|
error: new Error("Canonical feed transientById is not an object.")
|
|
@@ -4310,7 +4310,7 @@ function normalizeTransients(values) {
|
|
|
4310
4310
|
let error = null;
|
|
4311
4311
|
const byId = /* @__PURE__ */ new Map();
|
|
4312
4312
|
const idByOrdinal = /* @__PURE__ */ new Map();
|
|
4313
|
-
for (const [key, value] of Object.entries(
|
|
4313
|
+
for (const [key, value] of Object.entries(record2)) {
|
|
4314
4314
|
const item = normalizeTransientFeedItem(value);
|
|
4315
4315
|
if (!item || item.id !== key) {
|
|
4316
4316
|
error ||= new Error("Canonical feed contains an invalid transient item.");
|
|
@@ -5183,11 +5183,11 @@ function operationId(prefix) {
|
|
|
5183
5183
|
return randomUuid ? `${prefix}_${randomUuid}` : `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
5184
5184
|
}
|
|
5185
5185
|
function unwrapPublishedItem(value) {
|
|
5186
|
-
const
|
|
5187
|
-
const directItems = Array.isArray(
|
|
5188
|
-
const durable = asRecord(
|
|
5186
|
+
const record2 = asRecord(value);
|
|
5187
|
+
const directItems = Array.isArray(record2?.items) ? record2.items : [];
|
|
5188
|
+
const durable = asRecord(record2?.durable);
|
|
5189
5189
|
const durableItems = Array.isArray(durable?.items) ? durable.items : [];
|
|
5190
|
-
return
|
|
5190
|
+
return record2?.item || directItems[0] || durableItems[0] || value;
|
|
5191
5191
|
}
|
|
5192
5192
|
function requireFeedbackItem(value) {
|
|
5193
5193
|
const item = normalizeFeedItem(unwrapPublishedItem(value));
|
|
@@ -5227,14 +5227,14 @@ function createFeedPublisher(publish) {
|
|
|
5227
5227
|
get revision() {
|
|
5228
5228
|
return current.revision;
|
|
5229
5229
|
},
|
|
5230
|
-
update(
|
|
5230
|
+
update(text2, options = {}) {
|
|
5231
5231
|
const reservedOperationId = options.operationId || operationId("feed_transient_update");
|
|
5232
5232
|
const reservedOptions = { ...options };
|
|
5233
5233
|
return enqueueMutation(async () => {
|
|
5234
5234
|
const response = await publish("feed.transient.update", {
|
|
5235
5235
|
transientId: current.id,
|
|
5236
5236
|
expectedRevision: current.revision,
|
|
5237
|
-
text,
|
|
5237
|
+
text: text2,
|
|
5238
5238
|
...reservedOptions,
|
|
5239
5239
|
operationId: reservedOperationId
|
|
5240
5240
|
});
|
|
@@ -5242,14 +5242,14 @@ function createFeedPublisher(publish) {
|
|
|
5242
5242
|
return handle;
|
|
5243
5243
|
});
|
|
5244
5244
|
},
|
|
5245
|
-
settle(
|
|
5245
|
+
settle(text2, options = {}) {
|
|
5246
5246
|
const reservedOperationId = options.operationId || operationId("feed_transient_settle");
|
|
5247
5247
|
const reservedOptions = { ...options };
|
|
5248
5248
|
return enqueueMutation(async () => {
|
|
5249
5249
|
const response = await publish("feed.transient.settle", {
|
|
5250
5250
|
transientId: current.id,
|
|
5251
5251
|
expectedRevision: current.revision,
|
|
5252
|
-
...
|
|
5252
|
+
...text2 === void 0 ? {} : { text: text2 },
|
|
5253
5253
|
...reservedOptions,
|
|
5254
5254
|
operationId: reservedOperationId
|
|
5255
5255
|
});
|
|
@@ -5267,19 +5267,19 @@ function createFeedPublisher(publish) {
|
|
|
5267
5267
|
return handle;
|
|
5268
5268
|
};
|
|
5269
5269
|
return {
|
|
5270
|
-
async feedback(
|
|
5270
|
+
async feedback(text2, options = {}) {
|
|
5271
5271
|
return requireFeedbackItem(
|
|
5272
5272
|
await publish("feed.feedback", {
|
|
5273
|
-
text,
|
|
5273
|
+
text: text2,
|
|
5274
5274
|
...options,
|
|
5275
5275
|
operationId: options.operationId || operationId("feed_feedback")
|
|
5276
5276
|
})
|
|
5277
5277
|
);
|
|
5278
5278
|
},
|
|
5279
|
-
async transientFeedback(
|
|
5279
|
+
async transientFeedback(text2, options = {}) {
|
|
5280
5280
|
const item = requireTransientFeedbackItem(
|
|
5281
5281
|
await publish("feed.transient.create", {
|
|
5282
|
-
text,
|
|
5282
|
+
text: text2,
|
|
5283
5283
|
...options,
|
|
5284
5284
|
operationId: options.operationId || operationId("feed_transient_create")
|
|
5285
5285
|
})
|
|
@@ -5309,9 +5309,9 @@ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 5;
|
|
|
5309
5309
|
var DOCUMENT_RESYNC_CLOSE_CODE = 4e3;
|
|
5310
5310
|
var DOCUMENT_RESYNC_CLOSE_REASON = "Document resync required";
|
|
5311
5311
|
function documentVersion(document) {
|
|
5312
|
-
const
|
|
5313
|
-
const epochValue =
|
|
5314
|
-
const revisionValue =
|
|
5312
|
+
const record2 = document;
|
|
5313
|
+
const epochValue = record2.documentEpoch;
|
|
5314
|
+
const revisionValue = record2.documentRevision;
|
|
5315
5315
|
const epoch = epochValue === void 0 ? 0 : epochValue;
|
|
5316
5316
|
const revision = revisionValue === void 0 ? 0 : revisionValue;
|
|
5317
5317
|
if (!Number.isSafeInteger(epoch) || Number(epoch) < 0 || !Number.isSafeInteger(revision) || Number(revision) < 0) {
|
|
@@ -5333,11 +5333,43 @@ function stableDocumentFingerprint(value) {
|
|
|
5333
5333
|
if (Array.isArray(value)) {
|
|
5334
5334
|
return `[${value.map(stableDocumentFingerprint).join(",")}]`;
|
|
5335
5335
|
}
|
|
5336
|
-
const
|
|
5337
|
-
return `{${Object.keys(
|
|
5338
|
-
(key) => `${JSON.stringify(key)}:${stableDocumentFingerprint(
|
|
5336
|
+
const record2 = value;
|
|
5337
|
+
return `{${Object.keys(record2).sort().map(
|
|
5338
|
+
(key) => `${JSON.stringify(key)}:${stableDocumentFingerprint(record2[key])}`
|
|
5339
5339
|
).join(",")}}`;
|
|
5340
5340
|
}
|
|
5341
|
+
function canonicalDocumentFingerprint(value) {
|
|
5342
|
+
const stripPresentation = (input, path) => {
|
|
5343
|
+
if (input === null || typeof input !== "object") return input;
|
|
5344
|
+
if (input instanceof Date || input instanceof Uint8Array) return input;
|
|
5345
|
+
if (Array.isArray(input)) {
|
|
5346
|
+
return input.map((entry) => stripPresentation(entry, path));
|
|
5347
|
+
}
|
|
5348
|
+
const record2 = input;
|
|
5349
|
+
const output = {};
|
|
5350
|
+
for (const [key, entry] of Object.entries(record2)) {
|
|
5351
|
+
if (path.length === 1 && path[0] === "feed" && [
|
|
5352
|
+
"transientById",
|
|
5353
|
+
"feedbackUsageByJob",
|
|
5354
|
+
"revision",
|
|
5355
|
+
"lastTransientOrdinal"
|
|
5356
|
+
].includes(key)) {
|
|
5357
|
+
continue;
|
|
5358
|
+
}
|
|
5359
|
+
if (path.length === 3 && path[0] === "jobs" && path[1] === "byId" && [
|
|
5360
|
+
"actionTrace",
|
|
5361
|
+
"actionSummary",
|
|
5362
|
+
"actionSummaryText",
|
|
5363
|
+
"lastActionAt"
|
|
5364
|
+
].includes(key)) {
|
|
5365
|
+
continue;
|
|
5366
|
+
}
|
|
5367
|
+
output[key] = stripPresentation(entry, [...path, key]);
|
|
5368
|
+
}
|
|
5369
|
+
return output;
|
|
5370
|
+
};
|
|
5371
|
+
return stableDocumentFingerprint(stripPresentation(value, []));
|
|
5372
|
+
}
|
|
5341
5373
|
function debugWs(...args) {
|
|
5342
5374
|
if (DEBUG_WS) {
|
|
5343
5375
|
console.log(...args);
|
|
@@ -5655,6 +5687,7 @@ var WSClient = class {
|
|
|
5655
5687
|
}
|
|
5656
5688
|
this.lastInboundActivityAt = Date.now();
|
|
5657
5689
|
this.reconnectAttempts = 0;
|
|
5690
|
+
this.connectPromise = null;
|
|
5658
5691
|
this.emit("open", {});
|
|
5659
5692
|
finish();
|
|
5660
5693
|
};
|
|
@@ -5662,8 +5695,8 @@ var WSClient = class {
|
|
|
5662
5695
|
if (!isCurrent()) return;
|
|
5663
5696
|
this.lastInboundActivityAt = Date.now();
|
|
5664
5697
|
try {
|
|
5665
|
-
const
|
|
5666
|
-
this.handleMessage(JSON.parse(
|
|
5698
|
+
const text2 = typeof data === "string" ? data : data && typeof data === "object" && "toString" in data ? String(data.toString()) : "";
|
|
5699
|
+
this.handleMessage(JSON.parse(text2));
|
|
5667
5700
|
} catch (error) {
|
|
5668
5701
|
console.error("[Granular] Failed to parse message:", error);
|
|
5669
5702
|
}
|
|
@@ -5721,8 +5754,8 @@ var WSClient = class {
|
|
|
5721
5754
|
if (typeof reason === "string") return reason;
|
|
5722
5755
|
if (typeof reason === "object" && reason && "toString" in reason) {
|
|
5723
5756
|
try {
|
|
5724
|
-
const
|
|
5725
|
-
return
|
|
5757
|
+
const text2 = String(reason.toString());
|
|
5758
|
+
return text2 || void 0;
|
|
5726
5759
|
} catch {
|
|
5727
5760
|
return void 0;
|
|
5728
5761
|
}
|
|
@@ -5817,7 +5850,7 @@ var WSClient = class {
|
|
|
5817
5850
|
this.canonicalDocumentActivated = true;
|
|
5818
5851
|
}
|
|
5819
5852
|
}
|
|
5820
|
-
canAcceptDocumentReplacement(replacement, strictlyNewer) {
|
|
5853
|
+
canAcceptDocumentReplacement(replacement, strictlyNewer, options = {}) {
|
|
5821
5854
|
const replacementCanonical = isCanonicalSessionFeedDocument(replacement);
|
|
5822
5855
|
const currentCanonical = isCanonicalSessionFeedDocument(this.doc);
|
|
5823
5856
|
if (replacementCanonical) {
|
|
@@ -5866,7 +5899,7 @@ var WSClient = class {
|
|
|
5866
5899
|
debugWs(`[Granular DEBUG] Rejected session snapshot: ${canonicalError}`);
|
|
5867
5900
|
return false;
|
|
5868
5901
|
}
|
|
5869
|
-
if (this.canonicalDocumentActivated && incoming.epoch === current.epoch && incoming.revision === current.revision && !readSessionFeedSnapshot(this.doc).error && stableDocumentFingerprint(Automerge__namespace.toJS(replacement)) !== stableDocumentFingerprint(Automerge__namespace.toJS(this.doc))) {
|
|
5902
|
+
if (this.canonicalDocumentActivated && incoming.epoch === current.epoch && incoming.revision === current.revision && !readSessionFeedSnapshot(this.doc).error && (options.allowEqualRevisionPresentation ? canonicalDocumentFingerprint(Automerge__namespace.toJS(replacement)) : stableDocumentFingerprint(Automerge__namespace.toJS(replacement))) !== (options.allowEqualRevisionPresentation ? canonicalDocumentFingerprint(Automerge__namespace.toJS(this.doc)) : stableDocumentFingerprint(Automerge__namespace.toJS(this.doc)))) {
|
|
5870
5903
|
debugWs(
|
|
5871
5904
|
"[Granular DEBUG] Rejected divergent canonical snapshot at the accepted document version."
|
|
5872
5905
|
);
|
|
@@ -5988,6 +6021,7 @@ var WSClient = class {
|
|
|
5988
6021
|
reconnectScheduled: false
|
|
5989
6022
|
};
|
|
5990
6023
|
this.ws = null;
|
|
6024
|
+
this.connectPromise = null;
|
|
5991
6025
|
this.emit("close", info);
|
|
5992
6026
|
if (this.reconnectTimer) {
|
|
5993
6027
|
clearTimeout(this.reconnectTimer);
|
|
@@ -6025,13 +6059,89 @@ var WSClient = class {
|
|
|
6025
6059
|
);
|
|
6026
6060
|
return;
|
|
6027
6061
|
}
|
|
6062
|
+
if ("type" in message && message.type === "job_action_trace") {
|
|
6063
|
+
const update = message;
|
|
6064
|
+
if (typeof update.jobId !== "string" || update.jobId.length === 0 || !Number.isSafeInteger(update.documentEpoch) || update.documentEpoch < 0 || !Number.isSafeInteger(update.documentRevision) || update.documentRevision < 0 || !Array.isArray(update.actionTrace) || update.actionTrace.length > 128 || !update.actionTrace.every(
|
|
6065
|
+
(event) => event && typeof event === "object" && typeof event.id === "string" && typeof event.timestamp === "number" && Number.isFinite(event.timestamp)
|
|
6066
|
+
) || !Array.isArray(update.actionSummary) || update.actionSummary.length > 16 || !update.actionSummary.every((line) => typeof line === "string") || typeof update.actionSummaryText !== "string" || update.actionSummaryText.length > 8e3) {
|
|
6067
|
+
console.warn("[Granular] Ignoring invalid job_action_trace message");
|
|
6068
|
+
return;
|
|
6069
|
+
}
|
|
6070
|
+
const currentVersion = documentVersion(this.doc);
|
|
6071
|
+
if (update.documentEpoch < currentVersion.epoch || update.documentEpoch === currentVersion.epoch && update.documentRevision < currentVersion.revision) {
|
|
6072
|
+
return;
|
|
6073
|
+
}
|
|
6074
|
+
if (update.documentEpoch > currentVersion.epoch || update.documentEpoch === currentVersion.epoch && update.documentRevision > currentVersion.revision) {
|
|
6075
|
+
return;
|
|
6076
|
+
}
|
|
6077
|
+
const current = Automerge__namespace.toJS(this.doc);
|
|
6078
|
+
const job = current.jobs?.byId?.[update.jobId];
|
|
6079
|
+
if (job && typeof job === "object" && !Array.isArray(job)) {
|
|
6080
|
+
job.actionTrace = update.actionTrace;
|
|
6081
|
+
job.actionSummary = update.actionSummary;
|
|
6082
|
+
job.actionSummaryText = update.actionSummaryText;
|
|
6083
|
+
const lastEvent = update.actionTrace[update.actionTrace.length - 1];
|
|
6084
|
+
if (lastEvent && typeof lastEvent.timestamp === "number") {
|
|
6085
|
+
job.lastActionAt = lastEvent.timestamp;
|
|
6086
|
+
}
|
|
6087
|
+
this.doc = Automerge__namespace.from(current);
|
|
6088
|
+
this.emit("job_action_trace", update);
|
|
6089
|
+
this.emit("sync", this.doc);
|
|
6090
|
+
}
|
|
6091
|
+
return;
|
|
6092
|
+
}
|
|
6093
|
+
if ("type" in message && message.type === "feed_transient_patch") {
|
|
6094
|
+
const update = message;
|
|
6095
|
+
if (!Number.isSafeInteger(update.documentEpoch) || update.documentEpoch < 0 || !Number.isSafeInteger(update.documentRevision) || update.documentRevision < 0 || !Number.isSafeInteger(update.feedRevision) || update.feedRevision < 0 || !Number.isSafeInteger(update.lastTransientOrdinal) || update.lastTransientOrdinal < 0 || !Array.isArray(update.changes) || update.changes.length > 128 || !update.changes.every((change) => {
|
|
6096
|
+
if (!change || typeof change !== "object" || typeof change.transientId !== "string" || change.transientId.length === 0) {
|
|
6097
|
+
return false;
|
|
6098
|
+
}
|
|
6099
|
+
if (change.removed === true) return change.item === void 0;
|
|
6100
|
+
const item = change.item;
|
|
6101
|
+
return Boolean(
|
|
6102
|
+
item && typeof item === "object" && !Array.isArray(item) && item.id === change.transientId
|
|
6103
|
+
);
|
|
6104
|
+
})) {
|
|
6105
|
+
console.warn("[Granular] Ignoring invalid feed_transient_patch");
|
|
6106
|
+
return;
|
|
6107
|
+
}
|
|
6108
|
+
const currentVersion = documentVersion(this.doc);
|
|
6109
|
+
if (update.documentEpoch > currentVersion.epoch || update.documentEpoch === currentVersion.epoch && update.documentRevision > currentVersion.revision || update.documentEpoch < currentVersion.epoch || update.documentEpoch === currentVersion.epoch && update.documentRevision < currentVersion.revision) {
|
|
6110
|
+
return;
|
|
6111
|
+
}
|
|
6112
|
+
const current = Automerge__namespace.toJS(this.doc);
|
|
6113
|
+
const feed = current.feed;
|
|
6114
|
+
if (!feed || typeof feed !== "object" || Array.isArray(feed)) return;
|
|
6115
|
+
if (Number.isSafeInteger(feed.revision) && feed.revision > update.feedRevision) {
|
|
6116
|
+
return;
|
|
6117
|
+
}
|
|
6118
|
+
if (Number.isSafeInteger(feed.lastTransientOrdinal) && feed.lastTransientOrdinal > update.lastTransientOrdinal) {
|
|
6119
|
+
return;
|
|
6120
|
+
}
|
|
6121
|
+
if (!feed.transientById || typeof feed.transientById !== "object") {
|
|
6122
|
+
feed.transientById = {};
|
|
6123
|
+
}
|
|
6124
|
+
for (const change of update.changes) {
|
|
6125
|
+
if (change.removed === true) {
|
|
6126
|
+
delete feed.transientById[change.transientId];
|
|
6127
|
+
} else {
|
|
6128
|
+
feed.transientById[change.transientId] = change.item;
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
feed.revision = update.feedRevision;
|
|
6132
|
+
feed.lastTransientOrdinal = update.lastTransientOrdinal;
|
|
6133
|
+
this.doc = Automerge__namespace.from(current);
|
|
6134
|
+
this.emit("feed_transient_patch", update);
|
|
6135
|
+
this.emit("sync", this.doc);
|
|
6136
|
+
return;
|
|
6137
|
+
}
|
|
6028
6138
|
if ("type" in message && message.type === "snapshot_reset") {
|
|
6029
6139
|
const resetMessage = message;
|
|
6030
6140
|
try {
|
|
6031
|
-
if (!Number.isSafeInteger(resetMessage.documentEpoch) || resetMessage.documentEpoch <= 0 || !Number.isSafeInteger(resetMessage.documentRevision) || resetMessage.documentRevision < 0 || !Array.isArray(resetMessage.data)) {
|
|
6141
|
+
if (!Number.isSafeInteger(resetMessage.documentEpoch) || resetMessage.documentEpoch <= 0 || !Number.isSafeInteger(resetMessage.documentRevision) || resetMessage.documentRevision < 0 || !Array.isArray(resetMessage.data) && (!resetMessage.document || typeof resetMessage.document !== "object" || Array.isArray(resetMessage.document))) {
|
|
6032
6142
|
throw new Error("snapshot_reset metadata is invalid");
|
|
6033
6143
|
}
|
|
6034
|
-
const replacement = Automerge__namespace.load(
|
|
6144
|
+
const replacement = resetMessage.document ? Automerge__namespace.from(resetMessage.document) : Automerge__namespace.load(
|
|
6035
6145
|
this.decodeDocumentBytes(
|
|
6036
6146
|
resetMessage.data,
|
|
6037
6147
|
"Automerge snapshot_reset"
|
|
@@ -6045,7 +6155,10 @@ var WSClient = class {
|
|
|
6045
6155
|
"snapshot_reset metadata does not match the saved document"
|
|
6046
6156
|
);
|
|
6047
6157
|
}
|
|
6048
|
-
|
|
6158
|
+
const isJsonReplacement = Boolean(resetMessage.document);
|
|
6159
|
+
if (!this.canAcceptDocumentReplacement(replacement, !isJsonReplacement, {
|
|
6160
|
+
allowEqualRevisionPresentation: isJsonReplacement
|
|
6161
|
+
})) {
|
|
6049
6162
|
if (this.documentRepairRequired) {
|
|
6050
6163
|
this.requireDocumentResync(
|
|
6051
6164
|
"Stale Automerge snapshot_reset during document repair",
|
|
@@ -6338,30 +6451,30 @@ function parseJsonPromptChoiceOption(option) {
|
|
|
6338
6451
|
}
|
|
6339
6452
|
function normalizePromptChoiceOption(option) {
|
|
6340
6453
|
if (typeof option === "string") {
|
|
6341
|
-
const
|
|
6342
|
-
if (!
|
|
6454
|
+
const record3 = parseJsonPromptChoiceOption(option);
|
|
6455
|
+
if (!record3) {
|
|
6343
6456
|
return { value: option, label: option };
|
|
6344
6457
|
}
|
|
6345
|
-
const value2 = typeof
|
|
6458
|
+
const value2 = typeof record3.value === "string" ? record3.value : typeof record3.id === "string" ? record3.id : typeof record3.label === "string" ? record3.label : JSON.stringify(record3);
|
|
6346
6459
|
return {
|
|
6347
6460
|
value: value2,
|
|
6348
|
-
label: typeof
|
|
6349
|
-
description: typeof
|
|
6461
|
+
label: typeof record3.label === "string" ? record3.label : value2,
|
|
6462
|
+
description: typeof record3.description === "string" ? record3.description : void 0
|
|
6350
6463
|
};
|
|
6351
6464
|
}
|
|
6352
|
-
const
|
|
6353
|
-
if (!
|
|
6465
|
+
const record2 = option;
|
|
6466
|
+
if (!record2) {
|
|
6354
6467
|
return { value: "", label: "" };
|
|
6355
6468
|
}
|
|
6356
|
-
const nestedJson = (typeof
|
|
6469
|
+
const nestedJson = (typeof record2.value === "string" ? parseJsonPromptChoiceOption(record2.value) : null) || (typeof record2.label === "string" ? parseJsonPromptChoiceOption(record2.label) : null);
|
|
6357
6470
|
if (nestedJson) {
|
|
6358
6471
|
return normalizePromptChoiceOption(nestedJson);
|
|
6359
6472
|
}
|
|
6360
|
-
const value = typeof
|
|
6473
|
+
const value = typeof record2.value === "string" ? record2.value : typeof record2.label === "string" ? record2.label : JSON.stringify(record2);
|
|
6361
6474
|
return {
|
|
6362
6475
|
value,
|
|
6363
|
-
label: typeof
|
|
6364
|
-
description: typeof
|
|
6476
|
+
label: typeof record2.label === "string" ? record2.label : value,
|
|
6477
|
+
description: typeof record2.description === "string" ? record2.description : void 0
|
|
6365
6478
|
};
|
|
6366
6479
|
}
|
|
6367
6480
|
function scorePromptChoiceMatch(answer, answerTokens, option) {
|
|
@@ -6653,18 +6766,18 @@ var Session = class {
|
|
|
6653
6766
|
get revision() {
|
|
6654
6767
|
return current.revision;
|
|
6655
6768
|
},
|
|
6656
|
-
async update(
|
|
6769
|
+
async update(text2, options = {}) {
|
|
6657
6770
|
current = await track(
|
|
6658
|
-
current.update(
|
|
6771
|
+
current.update(text2, {
|
|
6659
6772
|
...options,
|
|
6660
6773
|
operationId: options.operationId || nextOperationId("transient-update")
|
|
6661
6774
|
})
|
|
6662
6775
|
);
|
|
6663
6776
|
return wrapped;
|
|
6664
6777
|
},
|
|
6665
|
-
settle(
|
|
6778
|
+
settle(text2, options = {}) {
|
|
6666
6779
|
return track(
|
|
6667
|
-
current.settle(
|
|
6780
|
+
current.settle(text2, {
|
|
6668
6781
|
...options,
|
|
6669
6782
|
operationId: options.operationId || nextOperationId("transient-settle")
|
|
6670
6783
|
})
|
|
@@ -6674,14 +6787,14 @@ var Session = class {
|
|
|
6674
6787
|
return wrapped;
|
|
6675
6788
|
};
|
|
6676
6789
|
return {
|
|
6677
|
-
feedback: (
|
|
6678
|
-
publisher.feedback(
|
|
6790
|
+
feedback: (text2, options = {}) => track(
|
|
6791
|
+
publisher.feedback(text2, {
|
|
6679
6792
|
...options,
|
|
6680
6793
|
operationId: options.operationId || nextOperationId("feedback")
|
|
6681
6794
|
})
|
|
6682
6795
|
),
|
|
6683
|
-
transientFeedback: (
|
|
6684
|
-
publisher.transientFeedback(
|
|
6796
|
+
transientFeedback: (text2, options = {}) => track(
|
|
6797
|
+
publisher.transientFeedback(text2, {
|
|
6685
6798
|
...options,
|
|
6686
6799
|
operationId: options.operationId || nextOperationId("transient-create")
|
|
6687
6800
|
}).then(wrapTransientHandle)
|
|
@@ -7869,8 +7982,8 @@ function artifactRecordsById(liveDoc) {
|
|
|
7869
7982
|
const byId = asRecord3(artifacts?.byId) || {};
|
|
7870
7983
|
return Object.fromEntries(
|
|
7871
7984
|
Object.entries(byId).map(([artifactId, value]) => {
|
|
7872
|
-
const
|
|
7873
|
-
return
|
|
7985
|
+
const record2 = asRecord3(value);
|
|
7986
|
+
return record2 ? [artifactId, record2] : null;
|
|
7874
7987
|
}).filter((entry) => Boolean(entry))
|
|
7875
7988
|
);
|
|
7876
7989
|
}
|
|
@@ -7903,8 +8016,8 @@ function latestInputEditSummary(metadata) {
|
|
|
7903
8016
|
].filter(Boolean);
|
|
7904
8017
|
return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
|
|
7905
8018
|
}
|
|
7906
|
-
function artifactIssueSummary(
|
|
7907
|
-
const validation = asRecord3(
|
|
8019
|
+
function artifactIssueSummary(record2) {
|
|
8020
|
+
const validation = asRecord3(record2.validation);
|
|
7908
8021
|
if (!validation) return null;
|
|
7909
8022
|
const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
|
|
7910
8023
|
if (issues.length > 0) {
|
|
@@ -7951,18 +8064,18 @@ function artifactStatePathSummary(metadata) {
|
|
|
7951
8064
|
].filter(Boolean);
|
|
7952
8065
|
return pieces.length ? pieces.join("; ") : null;
|
|
7953
8066
|
}
|
|
7954
|
-
function artifactSummaryLine(artifactId,
|
|
7955
|
-
if (!
|
|
7956
|
-
const label = trimString(
|
|
7957
|
-
const kind = asString(
|
|
7958
|
-
const status = asString(
|
|
7959
|
-
const createdByJobId = asString(
|
|
7960
|
-
const target = asRecord3(
|
|
7961
|
-
const metadata = asRecord3(
|
|
7962
|
-
const subArtifactIds = Array.isArray(
|
|
8067
|
+
function artifactSummaryLine(artifactId, record2) {
|
|
8068
|
+
if (!record2) return `- ${artifactId}: unavailable in session artifact store`;
|
|
8069
|
+
const label = trimString(record2.label) || artifactId;
|
|
8070
|
+
const kind = asString(record2.kind) || "artifact";
|
|
8071
|
+
const status = asString(record2.status) || "unknown";
|
|
8072
|
+
const createdByJobId = asString(record2.createdByJobId);
|
|
8073
|
+
const target = asRecord3(record2.target);
|
|
8074
|
+
const metadata = asRecord3(record2.metadata) || {};
|
|
8075
|
+
const subArtifactIds = Array.isArray(record2.subArtifactIds) ? record2.subArtifactIds.filter(
|
|
7963
8076
|
(id) => typeof id === "string" && id.trim().length > 0
|
|
7964
8077
|
).slice(0, 8) : [];
|
|
7965
|
-
const relationships = compactJson(
|
|
8078
|
+
const relationships = compactJson(record2.relationships, 220);
|
|
7966
8079
|
const pieces = [
|
|
7967
8080
|
`kind=${kind}`,
|
|
7968
8081
|
`status=${status}`,
|
|
@@ -7970,7 +8083,7 @@ function artifactSummaryLine(artifactId, record) {
|
|
|
7970
8083
|
target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
|
|
7971
8084
|
artifactStatePathSummary(metadata),
|
|
7972
8085
|
artifactExecutionSummary(metadata),
|
|
7973
|
-
artifactIssueSummary(
|
|
8086
|
+
artifactIssueSummary(record2),
|
|
7974
8087
|
latestInputEditSummary(metadata),
|
|
7975
8088
|
subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
|
|
7976
8089
|
relationships ? `relationships=${relationships}` : null
|
|
@@ -12390,6 +12503,7 @@ var StateMachineTransitionSchema = external_exports.object({
|
|
|
12390
12503
|
to: external_exports.string().min(1),
|
|
12391
12504
|
label: external_exports.string().optional(),
|
|
12392
12505
|
description: external_exports.string().optional(),
|
|
12506
|
+
userVisible: external_exports.boolean().optional(),
|
|
12393
12507
|
action: StateTransitionActionSchema.optional(),
|
|
12394
12508
|
assignee: StateTransitionAssigneeSchema.optional(),
|
|
12395
12509
|
requirements: StateTransitionRequirementsSchema.optional(),
|
|
@@ -12474,6 +12588,7 @@ var CreatesSchema = external_exports.union([
|
|
|
12474
12588
|
idPath: external_exports.string().min(1).optional(),
|
|
12475
12589
|
pathPath: external_exports.string().min(1).optional(),
|
|
12476
12590
|
statePath: external_exports.string().min(1).optional(),
|
|
12591
|
+
completionState: external_exports.string().min(1).optional(),
|
|
12477
12592
|
classStateHandle: external_exports.boolean().optional()
|
|
12478
12593
|
}).strict()
|
|
12479
12594
|
]);
|
|
@@ -12823,6 +12938,7 @@ function normalizeCreationSummary(metamodels) {
|
|
|
12823
12938
|
...typeof raw.idPath === "string" && raw.idPath.trim() ? { idPath: raw.idPath.trim() } : {},
|
|
12824
12939
|
...typeof raw.pathPath === "string" && raw.pathPath.trim() ? { pathPath: raw.pathPath.trim() } : {},
|
|
12825
12940
|
...typeof raw.statePath === "string" && raw.statePath.trim() ? { statePath: raw.statePath.trim() } : {},
|
|
12941
|
+
...typeof raw.completionState === "string" && raw.completionState.trim() ? { completionState: raw.completionState.trim() } : {},
|
|
12826
12942
|
...typeof raw.classStateHandle === "boolean" ? { classStateHandle: raw.classStateHandle } : {}
|
|
12827
12943
|
};
|
|
12828
12944
|
}
|
|
@@ -12948,7 +13064,7 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
12948
13064
|
},
|
|
12949
13065
|
{
|
|
12950
13066
|
key: "creates",
|
|
12951
|
-
description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, classStateHandle }`.'
|
|
13067
|
+
description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, completionState, classStateHandle }`.'
|
|
12952
13068
|
}
|
|
12953
13069
|
]
|
|
12954
13070
|
},
|
|
@@ -13171,18 +13287,18 @@ function validateScalarRecord(value, path) {
|
|
|
13171
13287
|
}
|
|
13172
13288
|
function validateProjectedRecord(value, path) {
|
|
13173
13289
|
validateObjectReference(value, path);
|
|
13174
|
-
const
|
|
13175
|
-
if (
|
|
13176
|
-
if (typeof
|
|
13290
|
+
const record2 = value;
|
|
13291
|
+
if (record2.label !== void 0) {
|
|
13292
|
+
if (typeof record2.label !== "string") {
|
|
13177
13293
|
throw new Error(`${path}.label must be a string`);
|
|
13178
13294
|
}
|
|
13179
|
-
if (
|
|
13295
|
+
if (record2.label.length > MAX_SAFE_TEXT_LENGTH) {
|
|
13180
13296
|
throw new Error(
|
|
13181
13297
|
`${path}.label exceeds ${MAX_SAFE_TEXT_LENGTH} characters`
|
|
13182
13298
|
);
|
|
13183
13299
|
}
|
|
13184
13300
|
}
|
|
13185
|
-
validateScalarRecord(
|
|
13301
|
+
validateScalarRecord(record2.fields, `${path}.fields`);
|
|
13186
13302
|
}
|
|
13187
13303
|
function validateBoundedJson(value, path, depth = 0) {
|
|
13188
13304
|
if (depth > 12) throw new Error(`${path} is nested too deeply`);
|
|
@@ -13232,6 +13348,11 @@ function validateProjectionResult(declaration, projection) {
|
|
|
13232
13348
|
"projection.source.version"
|
|
13233
13349
|
);
|
|
13234
13350
|
}
|
|
13351
|
+
if (projection.source.versionScope !== void 0 && projection.source.versionScope !== "global" && projection.source.versionScope !== "target") {
|
|
13352
|
+
throw new Error(
|
|
13353
|
+
"projection.source.versionScope must be 'global' or 'target'"
|
|
13354
|
+
);
|
|
13355
|
+
}
|
|
13235
13356
|
if (!Array.isArray(projection.changes)) {
|
|
13236
13357
|
throw new Error("projection.changes must be an array");
|
|
13237
13358
|
}
|
|
@@ -13595,18 +13716,18 @@ function createInvocationFeedbackContext(bridge) {
|
|
|
13595
13716
|
get revision() {
|
|
13596
13717
|
return current.revision;
|
|
13597
13718
|
},
|
|
13598
|
-
async update(
|
|
13719
|
+
async update(text2, options = {}) {
|
|
13599
13720
|
current = await track(
|
|
13600
|
-
current.update(
|
|
13721
|
+
current.update(text2, {
|
|
13601
13722
|
...options,
|
|
13602
13723
|
operationId: options.operationId || nextOperationId("transient-update")
|
|
13603
13724
|
})
|
|
13604
13725
|
);
|
|
13605
13726
|
return wrapped;
|
|
13606
13727
|
},
|
|
13607
|
-
settle(
|
|
13728
|
+
settle(text2, options = {}) {
|
|
13608
13729
|
return track(
|
|
13609
|
-
current.settle(
|
|
13730
|
+
current.settle(text2, {
|
|
13610
13731
|
...options,
|
|
13611
13732
|
operationId: options.operationId || nextOperationId("transient-settle")
|
|
13612
13733
|
})
|
|
@@ -13616,17 +13737,17 @@ function createInvocationFeedbackContext(bridge) {
|
|
|
13616
13737
|
return wrapped;
|
|
13617
13738
|
};
|
|
13618
13739
|
return {
|
|
13619
|
-
feedback(
|
|
13740
|
+
feedback(text2, options = {}) {
|
|
13620
13741
|
return track(
|
|
13621
|
-
publisher.feedback(
|
|
13742
|
+
publisher.feedback(text2, {
|
|
13622
13743
|
...options,
|
|
13623
13744
|
operationId: options.operationId || nextOperationId("feedback")
|
|
13624
13745
|
})
|
|
13625
13746
|
);
|
|
13626
13747
|
},
|
|
13627
|
-
transientFeedback(
|
|
13748
|
+
transientFeedback(text2, options = {}) {
|
|
13628
13749
|
return track(
|
|
13629
|
-
publisher.transientFeedback(
|
|
13750
|
+
publisher.transientFeedback(text2, {
|
|
13630
13751
|
...options,
|
|
13631
13752
|
operationId: options.operationId || nextOperationId("transient-create")
|
|
13632
13753
|
}).then(wrapTransientHandle)
|
|
@@ -14474,9 +14595,9 @@ var noteMetamodelPackage = defineMetamodelPackage({
|
|
|
14474
14595
|
notes: async (ant) => await run(ant.notes())
|
|
14475
14596
|
},
|
|
14476
14597
|
ModelMutation: {
|
|
14477
|
-
add_note: async (ant, { text }) => {
|
|
14478
|
-
const model = await run(ant.add_note(
|
|
14479
|
-
return { model, text };
|
|
14598
|
+
add_note: async (ant, { text: text2 }) => {
|
|
14599
|
+
const model = await run(ant.add_note(text2));
|
|
14600
|
+
return { model, text: text2 };
|
|
14480
14601
|
}
|
|
14481
14602
|
}
|
|
14482
14603
|
};
|
|
@@ -14889,6 +15010,7 @@ function normalizeStateMachines(values) {
|
|
|
14889
15010
|
to: String(transition?.to?.name || ""),
|
|
14890
15011
|
label: typeof transition?.label === "string" ? transition.label : null,
|
|
14891
15012
|
description: typeof transition?.description === "string" ? transition.description : null,
|
|
15013
|
+
userVisible: typeof transition?.user_visible === "boolean" ? transition.user_visible : typeof transition?.userVisible === "boolean" ? transition.userVisible : null,
|
|
14892
15014
|
action: parseJsonRecord(transition?.action) || parseJsonRecord(transition?.action_json),
|
|
14893
15015
|
assignee: parseJsonRecord(transition?.assignee) || parseJsonRecord(transition?.assignee_json),
|
|
14894
15016
|
requirements: parseJsonRecord(transition?.requirements) || parseJsonRecord(transition?.requirements_json),
|
|
@@ -14960,6 +15082,9 @@ function transitionMetadataGraphqlArgs(transition) {
|
|
|
14960
15082
|
if (typeof transition.description === "string") {
|
|
14961
15083
|
args.push(`description: ${JSON.stringify(transition.description)}`);
|
|
14962
15084
|
}
|
|
15085
|
+
if (typeof transition.userVisible === "boolean") {
|
|
15086
|
+
args.push(`user_visible: ${transition.userVisible}`);
|
|
15087
|
+
}
|
|
14963
15088
|
if (transition.action) {
|
|
14964
15089
|
args.push(
|
|
14965
15090
|
`action_json: ${JSON.stringify(JSON.stringify(transition.action))}`
|
|
@@ -15271,7 +15396,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15271
15396
|
name: String!
|
|
15272
15397
|
state_machine: StateMachine!
|
|
15273
15398
|
add_state(name: String!, is_final: Boolean, label: String, description: String): StateMachineMutation!
|
|
15274
|
-
add_transition(name: String!, from: String!, to: String!, label: String, description: String, action_json: String, assignee_json: String, requirements_json: String, permission_json: String, risk: String, expected_outcome_json: String, outcomes_json: String): StateMachineMutation!
|
|
15399
|
+
add_transition(name: String!, from: String!, to: String!, label: String, description: String, user_visible: Boolean, action_json: String, assignee_json: String, requirements_json: String, permission_json: String, risk: String, expected_outcome_json: String, outcomes_json: String): StateMachineMutation!
|
|
15275
15400
|
activate_transition(name: String!): StateMachineMutation!
|
|
15276
15401
|
}
|
|
15277
15402
|
|
|
@@ -15329,6 +15454,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15329
15454
|
to: StateMachineState!
|
|
15330
15455
|
label: String
|
|
15331
15456
|
description: String
|
|
15457
|
+
user_visible: Boolean
|
|
15332
15458
|
action_json: String
|
|
15333
15459
|
assignee_json: String
|
|
15334
15460
|
requirements_json: String
|
|
@@ -15410,6 +15536,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15410
15536
|
to,
|
|
15411
15537
|
label,
|
|
15412
15538
|
description,
|
|
15539
|
+
user_visible,
|
|
15413
15540
|
action_json,
|
|
15414
15541
|
assignee_json,
|
|
15415
15542
|
requirements_json,
|
|
@@ -15427,6 +15554,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15427
15554
|
{
|
|
15428
15555
|
label,
|
|
15429
15556
|
description,
|
|
15557
|
+
userVisible: user_visible,
|
|
15430
15558
|
actionJson: action_json,
|
|
15431
15559
|
assigneeJson: assignee_json,
|
|
15432
15560
|
requirementsJson: requirements_json,
|
|
@@ -15491,6 +15619,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15491
15619
|
to: (value) => value.to_state || { name: value.to, is_final: false },
|
|
15492
15620
|
label: (value) => value.label || null,
|
|
15493
15621
|
description: (value) => value.description || null,
|
|
15622
|
+
user_visible: (value) => value.user_visible ?? null,
|
|
15494
15623
|
action_json: (value) => value.action_json || null,
|
|
15495
15624
|
assignee_json: (value) => value.assignee_json || null,
|
|
15496
15625
|
requirements_json: (value) => value.requirements_json || null,
|
|
@@ -15577,6 +15706,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15577
15706
|
to { name }
|
|
15578
15707
|
label
|
|
15579
15708
|
description
|
|
15709
|
+
user_visible
|
|
15580
15710
|
action_json
|
|
15581
15711
|
assignee_json
|
|
15582
15712
|
requirements_json
|
|
@@ -15984,6 +16114,786 @@ function buildEffectMetamodelMutations(toolPath, spec) {
|
|
|
15984
16114
|
);
|
|
15985
16115
|
}
|
|
15986
16116
|
|
|
16117
|
+
// src/artifact-workflow.ts
|
|
16118
|
+
var TERMINAL_ARTIFACT_STATUSES = /* @__PURE__ */ new Set([
|
|
16119
|
+
"completed",
|
|
16120
|
+
"partially_completed",
|
|
16121
|
+
"failed",
|
|
16122
|
+
"canceled"
|
|
16123
|
+
]);
|
|
16124
|
+
function record(value) {
|
|
16125
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
16126
|
+
}
|
|
16127
|
+
function text(value) {
|
|
16128
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
16129
|
+
}
|
|
16130
|
+
function humanize(value) {
|
|
16131
|
+
const words = value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
16132
|
+
return words ? words[0].toUpperCase() + words.slice(1) : "Details";
|
|
16133
|
+
}
|
|
16134
|
+
function stableToken(value) {
|
|
16135
|
+
return encodeURIComponent(value.trim().toLowerCase());
|
|
16136
|
+
}
|
|
16137
|
+
function isMissing(value) {
|
|
16138
|
+
return value === null || value === void 0 || typeof value === "string" && !value.trim() || Array.isArray(value) && value.length === 0;
|
|
16139
|
+
}
|
|
16140
|
+
function displayValue(value) {
|
|
16141
|
+
if (typeof value === "string") return value;
|
|
16142
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
16143
|
+
return String(value);
|
|
16144
|
+
}
|
|
16145
|
+
if (Array.isArray(value)) {
|
|
16146
|
+
return value.map(displayValue).filter(Boolean).join(", ");
|
|
16147
|
+
}
|
|
16148
|
+
return "Provided";
|
|
16149
|
+
}
|
|
16150
|
+
function artifactFields(artifact) {
|
|
16151
|
+
return Array.isArray(artifact.inputSchema?.fields) ? artifact.inputSchema.fields.filter(
|
|
16152
|
+
(field) => Boolean(record(field))
|
|
16153
|
+
) : [];
|
|
16154
|
+
}
|
|
16155
|
+
function declaredSections(artifact) {
|
|
16156
|
+
const fields = artifactFields(artifact);
|
|
16157
|
+
if (!fields.length) return [];
|
|
16158
|
+
const knownNames = new Set(
|
|
16159
|
+
fields.map((field) => text(field.name)).filter((name) => Boolean(name))
|
|
16160
|
+
);
|
|
16161
|
+
const ui = record(artifact.inputSchema?.ui);
|
|
16162
|
+
const workflow = record(ui?.workflow);
|
|
16163
|
+
const rawSections = Array.isArray(workflow?.steps) ? workflow.steps : Array.isArray(ui?.sections) ? ui.sections : [];
|
|
16164
|
+
const used = /* @__PURE__ */ new Set();
|
|
16165
|
+
const sections = rawSections.flatMap((value) => {
|
|
16166
|
+
const section = record(value);
|
|
16167
|
+
const id = text(section?.id);
|
|
16168
|
+
const label = text(section?.label);
|
|
16169
|
+
const fieldNames = Array.isArray(section?.fieldNames) ? section.fieldNames.map(text).filter(
|
|
16170
|
+
(name) => name !== null && knownNames.has(name) && !used.has(name)
|
|
16171
|
+
) : [];
|
|
16172
|
+
if (!id || !label || !fieldNames.length) return [];
|
|
16173
|
+
fieldNames.forEach((name) => used.add(name));
|
|
16174
|
+
return [{ id, label, description: text(section?.description), fieldNames }];
|
|
16175
|
+
});
|
|
16176
|
+
const remaining = [...knownNames].filter((name) => !used.has(name));
|
|
16177
|
+
const chunkSize = 5;
|
|
16178
|
+
const chunkCount = Math.ceil(remaining.length / chunkSize);
|
|
16179
|
+
const hasDeclaredSections = sections.length > 0;
|
|
16180
|
+
for (let index = 0; index < chunkCount; index += 1) {
|
|
16181
|
+
const baseLabel = hasDeclaredSections ? "Other details" : "Details";
|
|
16182
|
+
sections.push({
|
|
16183
|
+
id: chunkCount === 1 ? hasDeclaredSections ? "other-details" : "details" : `${hasDeclaredSections ? "other-details" : "details"}-${index + 1}`,
|
|
16184
|
+
label: chunkCount === 1 ? baseLabel : `${baseLabel} ${index + 1}`,
|
|
16185
|
+
description: null,
|
|
16186
|
+
fieldNames: remaining.slice(index * chunkSize, (index + 1) * chunkSize)
|
|
16187
|
+
});
|
|
16188
|
+
}
|
|
16189
|
+
return sections;
|
|
16190
|
+
}
|
|
16191
|
+
function fieldValue(artifact, fieldName) {
|
|
16192
|
+
const field = artifactFields(artifact).find(
|
|
16193
|
+
(candidate) => text(candidate.name) === fieldName
|
|
16194
|
+
);
|
|
16195
|
+
const kind = text(field?.kind);
|
|
16196
|
+
return kind === "relationshipOne" || kind === "relationshipMany" ? artifact.relationships?.[fieldName] : artifact.inputValues?.[fieldName];
|
|
16197
|
+
}
|
|
16198
|
+
function conditionallyRequired(artifact, field) {
|
|
16199
|
+
const raw = field.requiredWhen ?? field.required_when;
|
|
16200
|
+
const conditions = Array.isArray(raw) ? raw : raw ? [raw] : [];
|
|
16201
|
+
return conditions.length > 0 && conditions.every((value) => {
|
|
16202
|
+
const condition = record(value);
|
|
16203
|
+
const dependency = text(condition?.field);
|
|
16204
|
+
return Boolean(dependency) && Object.prototype.hasOwnProperty.call(condition || {}, "equals") && Object.is(fieldValue(artifact, dependency), condition.equals);
|
|
16205
|
+
});
|
|
16206
|
+
}
|
|
16207
|
+
function fieldValidationRules(field) {
|
|
16208
|
+
const raw = Array.isArray(field.validationRules) ? field.validationRules : Array.isArray(field.validation_rules) ? field.validation_rules : Array.isArray(field.validate) ? field.validate : [];
|
|
16209
|
+
return raw.filter(
|
|
16210
|
+
(rule) => Boolean(record(rule)) && typeof record(rule)?.operator === "string"
|
|
16211
|
+
);
|
|
16212
|
+
}
|
|
16213
|
+
function fieldProvenanceNeedsReview(artifact, field) {
|
|
16214
|
+
const fieldName = text(field.name);
|
|
16215
|
+
if (!fieldName) return false;
|
|
16216
|
+
const namespace = text(field.kind)?.startsWith("relationship") ? "relationships" : "inputValues";
|
|
16217
|
+
const provenance = artifact.fieldProvenance?.[`${namespace}.${fieldName}`];
|
|
16218
|
+
if (!provenance) return false;
|
|
16219
|
+
const confirmedAt = typeof provenance.confirmedAt === "number" ? provenance.confirmedAt : null;
|
|
16220
|
+
const updatedAt = typeof provenance.updatedAt === "number" ? provenance.updatedAt : null;
|
|
16221
|
+
const invalidatedAt = typeof provenance.invalidatedAt === "number" ? provenance.invalidatedAt : null;
|
|
16222
|
+
const explicitlyConfirmed = confirmedAt !== null && (updatedAt === null || confirmedAt >= updatedAt) && (invalidatedAt === null || confirmedAt >= invalidatedAt);
|
|
16223
|
+
if (explicitlyConfirmed) return false;
|
|
16224
|
+
const invalidated = invalidatedAt !== null && (confirmedAt === null || confirmedAt < invalidatedAt);
|
|
16225
|
+
const assistantSource = [
|
|
16226
|
+
"user_statement",
|
|
16227
|
+
"agent_extraction",
|
|
16228
|
+
"agent_inference",
|
|
16229
|
+
"provider_lookup",
|
|
16230
|
+
"ontology_default"
|
|
16231
|
+
].includes(provenance.source);
|
|
16232
|
+
return invalidated || assistantSource && provenance.confidence === "ambiguous";
|
|
16233
|
+
}
|
|
16234
|
+
function sectionComplete(artifact, fieldNames) {
|
|
16235
|
+
const schema = record(artifact.inputSchema);
|
|
16236
|
+
const declaredRequiredNames = new Set(
|
|
16237
|
+
[
|
|
16238
|
+
...Array.isArray(schema?.required) ? schema.required : [],
|
|
16239
|
+
...Array.isArray(schema?.["x-granular-artifact-required"]) ? schema["x-granular-artifact-required"] : []
|
|
16240
|
+
].map(text).filter((name) => Boolean(name))
|
|
16241
|
+
);
|
|
16242
|
+
const validation = record(artifact.validation);
|
|
16243
|
+
const invalidFieldNames = new Set(
|
|
16244
|
+
(Array.isArray(validation?.issues) ? validation.issues : []).map(record).filter((issue) => Boolean(issue)).map((issue) => text(issue.path) || text(issue.field)).filter((path) => Boolean(path)).map((path) => path.replace(/^(inputValues|relationships)\./, ""))
|
|
16245
|
+
);
|
|
16246
|
+
const fieldsByName = new Map(
|
|
16247
|
+
artifactFields(artifact).map((field) => [text(field.name), field])
|
|
16248
|
+
);
|
|
16249
|
+
return fieldNames.every((fieldName) => {
|
|
16250
|
+
if (invalidFieldNames.has(fieldName)) return false;
|
|
16251
|
+
const field = fieldsByName.get(fieldName);
|
|
16252
|
+
if (!field) return true;
|
|
16253
|
+
if (fieldProvenanceNeedsReview(artifact, field)) return false;
|
|
16254
|
+
const required = declaredRequiredNames.has(fieldName) || field.required === true || conditionallyRequired(artifact, field);
|
|
16255
|
+
const value = fieldValue(artifact, fieldName);
|
|
16256
|
+
const provenance = artifact.fieldProvenance?.[`${text(field.kind)?.startsWith("relationship") ? "relationships" : "inputValues"}.${fieldName}`];
|
|
16257
|
+
if (provenance?.invalidatedAt) return false;
|
|
16258
|
+
if (text(field.kind)?.startsWith("relationship")) {
|
|
16259
|
+
const resolvers = record(
|
|
16260
|
+
record(artifact.metadata)?.relationshipResolvers
|
|
16261
|
+
);
|
|
16262
|
+
const resolverStatus = text(record(resolvers?.[fieldName])?.status);
|
|
16263
|
+
if (resolverStatus === "missing") return false;
|
|
16264
|
+
if (resolverStatus === "choice" && isMissing(value)) return false;
|
|
16265
|
+
}
|
|
16266
|
+
if (required && isMissing(value)) return false;
|
|
16267
|
+
if (isMissing(value)) return true;
|
|
16268
|
+
return fieldValidationRules(field).every(
|
|
16269
|
+
(rule) => evaluateValidationRule(value, rule).passed
|
|
16270
|
+
);
|
|
16271
|
+
});
|
|
16272
|
+
}
|
|
16273
|
+
function sectionRecap(artifact, fieldNames) {
|
|
16274
|
+
const fields = artifactFields(artifact);
|
|
16275
|
+
const fieldsByName = new Map(
|
|
16276
|
+
fields.map((field) => [text(field.name), field])
|
|
16277
|
+
);
|
|
16278
|
+
const labels = new Map(
|
|
16279
|
+
fields.map((field) => [
|
|
16280
|
+
text(field.name),
|
|
16281
|
+
text(field.label) || humanize(text(field.name) || "detail")
|
|
16282
|
+
])
|
|
16283
|
+
);
|
|
16284
|
+
const items = fieldNames.flatMap((fieldName) => {
|
|
16285
|
+
const value = fieldValue(artifact, fieldName);
|
|
16286
|
+
if (isMissing(value)) return [];
|
|
16287
|
+
const field = fieldsByName.get(fieldName);
|
|
16288
|
+
const relationshipLabels = record(
|
|
16289
|
+
record(artifact.metadata)?.relationshipLabels
|
|
16290
|
+
);
|
|
16291
|
+
const fieldLabels = record(relationshipLabels?.[fieldName]);
|
|
16292
|
+
const resolvers = record(record(artifact.metadata)?.relationshipResolvers);
|
|
16293
|
+
const candidates = Array.isArray(record(resolvers?.[fieldName])?.candidates) ? record(resolvers?.[fieldName])?.candidates : [];
|
|
16294
|
+
const candidateLabel = candidates.map(record).find((candidate) => text(candidate?.id) === value)?.label;
|
|
16295
|
+
const rawOptions = Array.isArray(field?.enumOptions) ? field.enumOptions : Array.isArray(field?.options) ? field.options : [];
|
|
16296
|
+
const enumLabel = rawOptions.map(
|
|
16297
|
+
(option) => typeof option === "string" ? { value: option, label: humanize(option) } : record(option)
|
|
16298
|
+
).find((option) => text(option?.value) === value)?.label;
|
|
16299
|
+
const rendered = typeof value === "string" && text(fieldLabels?.[value]) ? text(fieldLabels?.[value]) : typeof value === "string" && text(candidateLabel) ? text(candidateLabel) : typeof value === "string" && text(enumLabel) ? text(enumLabel) : typeof value === "string" && (text(field?.kind) === "enum" || text(field?.kind)?.startsWith("relationship")) ? humanize(value) : displayValue(value);
|
|
16300
|
+
return [
|
|
16301
|
+
{ label: labels.get(fieldName) || humanize(fieldName), value: rendered }
|
|
16302
|
+
];
|
|
16303
|
+
});
|
|
16304
|
+
return {
|
|
16305
|
+
summary: items.length ? items.map((item) => `${item.label}: ${item.value}`).join(" \xB7 ") : "Completed",
|
|
16306
|
+
items
|
|
16307
|
+
};
|
|
16308
|
+
}
|
|
16309
|
+
function operationPhase(artifact) {
|
|
16310
|
+
const execution = record(record(artifact.metadata)?.execution);
|
|
16311
|
+
const phase = text(execution?.phase);
|
|
16312
|
+
if (artifact.status === "completed") return "completed";
|
|
16313
|
+
if (artifact.status === "failed") return "failed";
|
|
16314
|
+
if (artifact.status === "awaiting_human") return "waiting_for_approval";
|
|
16315
|
+
if (phase === "preparing") return "reviewing";
|
|
16316
|
+
if (phase === "syncing_record") return "synchronizing";
|
|
16317
|
+
if (phase === "verifying_target") return "verifying";
|
|
16318
|
+
if (artifact.status === "running") return "sending";
|
|
16319
|
+
return null;
|
|
16320
|
+
}
|
|
16321
|
+
function operationLabel(artifact) {
|
|
16322
|
+
const ui = record(artifact.inputSchema?.ui);
|
|
16323
|
+
const workflow = record(ui?.workflow);
|
|
16324
|
+
const effect = record(record(artifact.metadata)?.effect);
|
|
16325
|
+
return text(workflow?.operationLabel) || text(ui?.submitLabel) || text(effect?.activityLabel) || text(effect?.label) || artifact.label;
|
|
16326
|
+
}
|
|
16327
|
+
function relationshipValueContainsRecordId(value, recordId) {
|
|
16328
|
+
return Array.isArray(value) ? value.some((item) => item === recordId) : value === recordId;
|
|
16329
|
+
}
|
|
16330
|
+
function relationshipChildLinkPending(parent, fieldName, child) {
|
|
16331
|
+
if (child.status !== "completed") return false;
|
|
16332
|
+
const parentMetadata = record(parent.metadata);
|
|
16333
|
+
const linkMarker = record(
|
|
16334
|
+
record(parentMetadata?.relationshipLinkProvenance)?.[fieldName]
|
|
16335
|
+
);
|
|
16336
|
+
const relationshipValue = parent.relationships?.[fieldName];
|
|
16337
|
+
const childExecution = record(record(child.metadata)?.execution);
|
|
16338
|
+
const childResult = record(childExecution?.result);
|
|
16339
|
+
const childCommit = record(childResult?.commit);
|
|
16340
|
+
const primaryTarget2 = record(childCommit?.primaryTarget);
|
|
16341
|
+
const committedRecordId = text(primaryTarget2?.id);
|
|
16342
|
+
const markerRecordId = text(linkMarker?.recordId);
|
|
16343
|
+
const exactRecordId = markerRecordId || committedRecordId;
|
|
16344
|
+
if (exactRecordId) {
|
|
16345
|
+
return !relationshipValueContainsRecordId(relationshipValue, exactRecordId);
|
|
16346
|
+
}
|
|
16347
|
+
return isMissing(relationshipValue);
|
|
16348
|
+
}
|
|
16349
|
+
function stateTransitionSteps(artifact) {
|
|
16350
|
+
if (artifact.kind !== "state_path") return [];
|
|
16351
|
+
const statePlan = record(record(artifact.metadata)?.statePlan);
|
|
16352
|
+
const plan = record(statePlan?.plan);
|
|
16353
|
+
const transitionMetadata = record(statePlan?.transitionMetadata);
|
|
16354
|
+
const rawSteps = Array.isArray(statePlan?.steps) ? statePlan.steps : Array.isArray(plan?.steps) ? plan.steps : [];
|
|
16355
|
+
return Array.from(rawSteps).flatMap((value, fallbackIndex) => {
|
|
16356
|
+
const step = record(value);
|
|
16357
|
+
const transition = text(step?.transition);
|
|
16358
|
+
if (!step || !transition) return [];
|
|
16359
|
+
const transitionDescription = record(transitionMetadata?.[transition]);
|
|
16360
|
+
const userVisible = typeof step.userVisible === "boolean" ? step.userVisible : typeof transitionDescription?.userVisible === "boolean" ? transitionDescription.userVisible : true;
|
|
16361
|
+
const blockers = Array.isArray(step.blockers) ? step.blockers.filter(
|
|
16362
|
+
(blocker) => Boolean(record(blocker))
|
|
16363
|
+
) : [];
|
|
16364
|
+
return [
|
|
16365
|
+
{
|
|
16366
|
+
index: typeof step.index === "number" ? step.index : fallbackIndex,
|
|
16367
|
+
transition,
|
|
16368
|
+
label: text(step.label) || humanize(transition),
|
|
16369
|
+
description: text(step.description) || text(record(step.expectedOutcome)?.summary) || null,
|
|
16370
|
+
status: text(step.status) || "pending",
|
|
16371
|
+
// State plans may contain bookkeeping transitions that are necessary
|
|
16372
|
+
// for execution/audit but are already represented by an actionable
|
|
16373
|
+
// form or by the single final operation. Producers must opt those
|
|
16374
|
+
// transitions out explicitly; the client never infers this from a
|
|
16375
|
+
// label or transition name.
|
|
16376
|
+
userVisible,
|
|
16377
|
+
blockers
|
|
16378
|
+
}
|
|
16379
|
+
];
|
|
16380
|
+
});
|
|
16381
|
+
}
|
|
16382
|
+
function stateTransitionGroupLabel(artifact) {
|
|
16383
|
+
if (artifact.kind !== "state_path") return null;
|
|
16384
|
+
const statePlan = record(record(artifact.metadata)?.statePlan);
|
|
16385
|
+
const classLabel = text(statePlan?.classLabel);
|
|
16386
|
+
return classLabel ? `${classLabel} workflow` : null;
|
|
16387
|
+
}
|
|
16388
|
+
function workflowGroupStatus(nodes) {
|
|
16389
|
+
const active = nodes.find(
|
|
16390
|
+
(node) => ["current", "needs_input", "working", "blocked", "failed"].includes(
|
|
16391
|
+
node.status
|
|
16392
|
+
)
|
|
16393
|
+
);
|
|
16394
|
+
if (active) return active.status;
|
|
16395
|
+
if (nodes.some((node) => node.status === "upcoming")) return "upcoming";
|
|
16396
|
+
const lastTerminal = [...nodes].reverse().find((node) => isTerminalWorkflowStepStatus(node.status));
|
|
16397
|
+
return lastTerminal?.status || nodes[0]?.status || "upcoming";
|
|
16398
|
+
}
|
|
16399
|
+
function transitionNodeStatus(artifact, step) {
|
|
16400
|
+
const statePlan = record(record(artifact.metadata)?.statePlan);
|
|
16401
|
+
const currentStep = record(statePlan?.currentStep);
|
|
16402
|
+
const execution = record(record(artifact.metadata)?.execution);
|
|
16403
|
+
const currentTransition = text(execution?.currentTransition);
|
|
16404
|
+
const completedTransitions = new Set(
|
|
16405
|
+
Array.isArray(execution?.completedTransitions) ? execution.completedTransitions.map(text).filter((value) => Boolean(value)) : []
|
|
16406
|
+
);
|
|
16407
|
+
const isCurrent = currentTransition === step.transition || currentStep?.index === step.index;
|
|
16408
|
+
if (completedTransitions.has(step.transition) || step.status === "completed") {
|
|
16409
|
+
return "completed";
|
|
16410
|
+
}
|
|
16411
|
+
if (isCurrent && artifact.status === "failed") return "failed";
|
|
16412
|
+
if (isCurrent && artifact.status === "canceled") return "canceled";
|
|
16413
|
+
if (isCurrent && artifact.status === "running") return "working";
|
|
16414
|
+
if (step.status === "failed") return "failed";
|
|
16415
|
+
if (artifact.status === "canceled") return "canceled";
|
|
16416
|
+
if (step.status === "blocked") return "blocked";
|
|
16417
|
+
if (step.status === "needs_other_user" || step.status === "needs_input") {
|
|
16418
|
+
return "needs_input";
|
|
16419
|
+
}
|
|
16420
|
+
if (isCurrent || step.status === "ready" || step.status === "current") {
|
|
16421
|
+
return "current";
|
|
16422
|
+
}
|
|
16423
|
+
if (step.status === "skipped") return "skipped";
|
|
16424
|
+
if (step.status === "canceled") return "canceled";
|
|
16425
|
+
return "upcoming";
|
|
16426
|
+
}
|
|
16427
|
+
var TERMINAL_WORKFLOW_STEP_STATUSES = /* @__PURE__ */ new Set([
|
|
16428
|
+
"completed",
|
|
16429
|
+
"skipped",
|
|
16430
|
+
"canceled"
|
|
16431
|
+
]);
|
|
16432
|
+
function isArtifactWorkflowNodeTerminal(nodeOrStatus) {
|
|
16433
|
+
const status = typeof nodeOrStatus === "string" ? nodeOrStatus : nodeOrStatus.status;
|
|
16434
|
+
return TERMINAL_WORKFLOW_STEP_STATUSES.has(status);
|
|
16435
|
+
}
|
|
16436
|
+
function isTerminalWorkflowStepStatus(status) {
|
|
16437
|
+
return isArtifactWorkflowNodeTerminal(status);
|
|
16438
|
+
}
|
|
16439
|
+
function firstTransitionStatus(artifact, status) {
|
|
16440
|
+
if (status !== "upcoming") return status;
|
|
16441
|
+
if (artifact.status === "canceled") return "canceled";
|
|
16442
|
+
if (artifact.status === "failed") return "failed";
|
|
16443
|
+
if (artifact.status === "blocked" || artifact.status === "stale" || artifact.status === "partially_completed") {
|
|
16444
|
+
return "blocked";
|
|
16445
|
+
}
|
|
16446
|
+
if (artifact.status === "running") return "working";
|
|
16447
|
+
if (artifact.status === "awaiting_human") return "needs_input";
|
|
16448
|
+
return "current";
|
|
16449
|
+
}
|
|
16450
|
+
function operationStatus(artifact, transitionStatuses = []) {
|
|
16451
|
+
if (artifact.status === "completed") {
|
|
16452
|
+
if (transitionStatuses.some(
|
|
16453
|
+
(status) => !TERMINAL_WORKFLOW_STEP_STATUSES.has(status)
|
|
16454
|
+
)) {
|
|
16455
|
+
if (transitionStatuses.includes("failed")) return "failed";
|
|
16456
|
+
if (transitionStatuses.includes("needs_input")) return "needs_input";
|
|
16457
|
+
if (transitionStatuses.includes("working")) return "working";
|
|
16458
|
+
if (transitionStatuses.includes("current")) return "current";
|
|
16459
|
+
return "blocked";
|
|
16460
|
+
}
|
|
16461
|
+
return "completed";
|
|
16462
|
+
}
|
|
16463
|
+
if (artifact.status === "failed") return "failed";
|
|
16464
|
+
if (artifact.status === "canceled") return "canceled";
|
|
16465
|
+
if (artifact.status === "partially_completed") return "blocked";
|
|
16466
|
+
if (artifact.status === "blocked" || artifact.status === "stale")
|
|
16467
|
+
return "blocked";
|
|
16468
|
+
if (artifact.status === "running") return "working";
|
|
16469
|
+
if (artifact.status === "awaiting_human") return "needs_input";
|
|
16470
|
+
if (artifact.status === "ready") return "current";
|
|
16471
|
+
return "upcoming";
|
|
16472
|
+
}
|
|
16473
|
+
function semanticWorkflow(workflow) {
|
|
16474
|
+
const { revision: _revision, updatedAt: _updatedAt, ...semantic } = workflow;
|
|
16475
|
+
return semantic;
|
|
16476
|
+
}
|
|
16477
|
+
function isNavigationOnlyOperation(workflow, node) {
|
|
16478
|
+
const hasExplicitTransitionLeaf = getArtifactWorkflowNodes(workflow).some(
|
|
16479
|
+
(candidate) => candidate.childIds.length === 0 && candidate.kind === "transition"
|
|
16480
|
+
);
|
|
16481
|
+
return hasExplicitTransitionLeaf && node.childIds.length === 0 && node.kind === "operation" && // A terminal operation is redundant once authored state-path leaves are
|
|
16482
|
+
// available. While it is still delivering/synchronizing, however, it is
|
|
16483
|
+
// the only honest representation of the work still in progress.
|
|
16484
|
+
isArtifactWorkflowNodeTerminal(node);
|
|
16485
|
+
}
|
|
16486
|
+
function getArtifactWorkflowNavigationLeaves(workflow) {
|
|
16487
|
+
return getArtifactWorkflowNodes(workflow).filter(
|
|
16488
|
+
(node) => isArtifactWorkflowNodeNavigableLeaf(workflow, node)
|
|
16489
|
+
);
|
|
16490
|
+
}
|
|
16491
|
+
function isArtifactWorkflowNodeNavigableLeaf(workflow, node) {
|
|
16492
|
+
return node.childIds.length === 0 && !isNavigationOnlyOperation(workflow, node);
|
|
16493
|
+
}
|
|
16494
|
+
function isArtifactWorkflowNodeActionable(node) {
|
|
16495
|
+
return node.availability === "available" && ["current", "needs_input", "working", "blocked", "failed"].includes(
|
|
16496
|
+
node.status
|
|
16497
|
+
);
|
|
16498
|
+
}
|
|
16499
|
+
function getArtifactWorkflowNavigationTarget(workflow) {
|
|
16500
|
+
const leaves = getArtifactWorkflowNavigationLeaves(workflow);
|
|
16501
|
+
return leaves.find(
|
|
16502
|
+
(node) => !isArtifactWorkflowNodeTerminal(node) && isArtifactWorkflowNodeActionable(node)
|
|
16503
|
+
) || leaves.at(-1) || null;
|
|
16504
|
+
}
|
|
16505
|
+
function projectArtifactWorkflow(artifact, allArtifacts = [artifact], now = artifact.updatedAt) {
|
|
16506
|
+
const nodesById = {};
|
|
16507
|
+
const rootNodeIds = [];
|
|
16508
|
+
const sections = declaredSections(artifact);
|
|
16509
|
+
const children = new Map(
|
|
16510
|
+
allArtifacts.filter((candidate2) => candidate2.parentArtifactId === artifact.artifactId).map((candidate2) => [candidate2.artifactId, candidate2])
|
|
16511
|
+
);
|
|
16512
|
+
const relationshipChildren = record(
|
|
16513
|
+
record(artifact.metadata)?.relationshipChildren
|
|
16514
|
+
);
|
|
16515
|
+
const operationId2 = `${artifact.artifactId}:operation`;
|
|
16516
|
+
const validationId = `${artifact.artifactId}:validation`;
|
|
16517
|
+
const sectionNodeIds = [];
|
|
16518
|
+
let currentNodeId = null;
|
|
16519
|
+
let foundIncompleteSection = false;
|
|
16520
|
+
let foundActiveLeaf = false;
|
|
16521
|
+
let transitionHasActiveStep = false;
|
|
16522
|
+
let hasVisibleTransition = false;
|
|
16523
|
+
const projectedTransitionStatuses = [];
|
|
16524
|
+
const transitionNodeIds = [];
|
|
16525
|
+
const transitionGroupLabel = stateTransitionGroupLabel(artifact);
|
|
16526
|
+
const transitionGroupId = `${artifact.artifactId}:transition-group`;
|
|
16527
|
+
for (const section of sections) {
|
|
16528
|
+
const id = `${artifact.artifactId}:section:${stableToken(section.id)}`;
|
|
16529
|
+
const complete = sectionComplete(artifact, section.fieldNames);
|
|
16530
|
+
const blockedByEarlierSection = foundIncompleteSection;
|
|
16531
|
+
const blockedByEarlierAction = foundIncompleteSection || foundActiveLeaf;
|
|
16532
|
+
const relationshipFields = artifactFields(artifact).filter(
|
|
16533
|
+
(field) => section.fieldNames.includes(text(field.name) || "") && ["relationshipOne", "relationshipMany"].includes(
|
|
16534
|
+
text(field.kind) || ""
|
|
16535
|
+
)
|
|
16536
|
+
);
|
|
16537
|
+
const relationshipField = relationshipFields[0];
|
|
16538
|
+
const relationshipChildrenInSection = relationshipFields.flatMap(
|
|
16539
|
+
(field) => {
|
|
16540
|
+
const relationshipName = text(field.name);
|
|
16541
|
+
const childArtifactId = relationshipName ? text(relationshipChildren?.[relationshipName]) : null;
|
|
16542
|
+
const child = childArtifactId ? children.get(childArtifactId) : null;
|
|
16543
|
+
if (!relationshipName || !child) return [];
|
|
16544
|
+
return [
|
|
16545
|
+
{
|
|
16546
|
+
relationshipName,
|
|
16547
|
+
child,
|
|
16548
|
+
childLinkPending: relationshipChildLinkPending(
|
|
16549
|
+
artifact,
|
|
16550
|
+
relationshipName,
|
|
16551
|
+
child
|
|
16552
|
+
),
|
|
16553
|
+
childId: `${artifact.artifactId}:child:${stableToken(child.artifactId)}`
|
|
16554
|
+
}
|
|
16555
|
+
];
|
|
16556
|
+
}
|
|
16557
|
+
);
|
|
16558
|
+
const relationshipChildFieldNames = new Set(
|
|
16559
|
+
relationshipChildrenInSection.map(
|
|
16560
|
+
({ relationshipName }) => relationshipName
|
|
16561
|
+
)
|
|
16562
|
+
);
|
|
16563
|
+
const residualFieldNames = section.fieldNames.filter(
|
|
16564
|
+
(fieldName) => !relationshipChildFieldNames.has(fieldName)
|
|
16565
|
+
);
|
|
16566
|
+
const residualComplete = sectionComplete(artifact, residualFieldNames);
|
|
16567
|
+
const residualId = `${id}:details`;
|
|
16568
|
+
const childActive = relationshipChildrenInSection.some(
|
|
16569
|
+
({ child, childLinkPending }) => childLinkPending || !TERMINAL_ARTIFACT_STATUSES.has(child.status)
|
|
16570
|
+
);
|
|
16571
|
+
const childIsWorking = relationshipChildrenInSection.some(
|
|
16572
|
+
({ child, childLinkPending }) => childLinkPending || child.status === "running"
|
|
16573
|
+
);
|
|
16574
|
+
const sectionStatus = complete && !blockedByEarlierSection ? "completed" : blockedByEarlierAction ? "upcoming" : childActive ? childIsWorking ? "working" : "needs_input" : !TERMINAL_ARTIFACT_STATUSES.has(artifact.status) ? "needs_input" : "upcoming";
|
|
16575
|
+
if (!complete) foundIncompleteSection = true;
|
|
16576
|
+
nodesById[id] = {
|
|
16577
|
+
id,
|
|
16578
|
+
artifactId: artifact.artifactId,
|
|
16579
|
+
parentId: operationId2,
|
|
16580
|
+
childIds: [
|
|
16581
|
+
...relationshipChildrenInSection.map(({ childId }) => childId),
|
|
16582
|
+
...relationshipChildrenInSection.length > 0 && residualFieldNames.length > 0 && !residualComplete ? [residualId] : []
|
|
16583
|
+
],
|
|
16584
|
+
kind: relationshipChildrenInSection.length > 0 ? "group" : relationshipField ? "relationship" : "input",
|
|
16585
|
+
label: section.label,
|
|
16586
|
+
description: section.description,
|
|
16587
|
+
status: sectionStatus,
|
|
16588
|
+
availability: sectionStatus === "completed" ? "readonly" : sectionStatus === "upcoming" ? "unavailable" : "available",
|
|
16589
|
+
fieldNames: relationshipChildrenInSection.length > 0 ? void 0 : section.fieldNames,
|
|
16590
|
+
recap: sectionStatus === "completed" ? sectionRecap(artifact, section.fieldNames) : null,
|
|
16591
|
+
completedAt: sectionStatus === "completed" ? artifact.updatedAt : null
|
|
16592
|
+
};
|
|
16593
|
+
sectionNodeIds.push(id);
|
|
16594
|
+
const childStatuses = [];
|
|
16595
|
+
for (const {
|
|
16596
|
+
child,
|
|
16597
|
+
childId,
|
|
16598
|
+
childLinkPending
|
|
16599
|
+
} of relationshipChildrenInSection) {
|
|
16600
|
+
const authoritativeChildStatus = childLinkPending ? "working" : child.status === "completed" ? "completed" : child.status === "failed" ? "failed" : child.status === "canceled" ? "canceled" : child.status === "running" ? "working" : child.status === "blocked" || child.status === "stale" ? "blocked" : child.status === "ready" ? "current" : "needs_input";
|
|
16601
|
+
const childStatus = blockedByEarlierSection ? "upcoming" : foundActiveLeaf && !isTerminalWorkflowStepStatus(authoritativeChildStatus) ? "upcoming" : authoritativeChildStatus;
|
|
16602
|
+
childStatuses.push(childStatus);
|
|
16603
|
+
nodesById[childId] = {
|
|
16604
|
+
id: childId,
|
|
16605
|
+
artifactId: artifact.artifactId,
|
|
16606
|
+
parentId: id,
|
|
16607
|
+
childIds: [],
|
|
16608
|
+
kind: "child_artifact",
|
|
16609
|
+
label: child.label,
|
|
16610
|
+
description: child.description,
|
|
16611
|
+
status: childStatus,
|
|
16612
|
+
availability: childStatus === "completed" ? "readonly" : childStatus === "upcoming" ? "unavailable" : "available",
|
|
16613
|
+
childArtifactId: child.artifactId,
|
|
16614
|
+
recap: childStatus === "completed" ? { summary: `${child.label} completed`, items: [] } : null,
|
|
16615
|
+
attention: childStatus === "failed" ? { title: `${child.label} failed`, retryable: true } : null,
|
|
16616
|
+
startedAt: child.executedAt || null,
|
|
16617
|
+
completedAt: childLinkPending ? null : child.completedAt || null
|
|
16618
|
+
};
|
|
16619
|
+
if (!blockedByEarlierSection && !isArtifactWorkflowNodeTerminal(childStatus)) {
|
|
16620
|
+
if (!foundActiveLeaf) {
|
|
16621
|
+
currentNodeId = childId;
|
|
16622
|
+
foundActiveLeaf = true;
|
|
16623
|
+
}
|
|
16624
|
+
}
|
|
16625
|
+
}
|
|
16626
|
+
if (relationshipChildrenInSection.length > 0 && residualFieldNames.length > 0 && !residualComplete) {
|
|
16627
|
+
const residualStatus = residualComplete ? "completed" : blockedByEarlierSection || foundActiveLeaf ? "upcoming" : !TERMINAL_ARTIFACT_STATUSES.has(artifact.status) ? "needs_input" : "upcoming";
|
|
16628
|
+
const residualFields = artifactFields(artifact).filter(
|
|
16629
|
+
(field) => residualFieldNames.includes(text(field.name) || "")
|
|
16630
|
+
);
|
|
16631
|
+
const residualLabel = residualFields.length === 1 ? text(residualFields[0]?.label) || section.label : "Details";
|
|
16632
|
+
childStatuses.push(residualStatus);
|
|
16633
|
+
nodesById[residualId] = {
|
|
16634
|
+
id: residualId,
|
|
16635
|
+
artifactId: artifact.artifactId,
|
|
16636
|
+
parentId: id,
|
|
16637
|
+
childIds: [],
|
|
16638
|
+
kind: residualFields.some(
|
|
16639
|
+
(field) => ["relationshipOne", "relationshipMany"].includes(
|
|
16640
|
+
text(field.kind) || ""
|
|
16641
|
+
)
|
|
16642
|
+
) ? "relationship" : "input",
|
|
16643
|
+
label: residualLabel,
|
|
16644
|
+
description: section.description,
|
|
16645
|
+
status: residualStatus,
|
|
16646
|
+
availability: residualStatus === "completed" ? "readonly" : residualStatus === "upcoming" ? "unavailable" : "available",
|
|
16647
|
+
fieldNames: residualFieldNames,
|
|
16648
|
+
recap: residualComplete ? sectionRecap(artifact, residualFieldNames) : null,
|
|
16649
|
+
completedAt: residualComplete ? artifact.updatedAt : null
|
|
16650
|
+
};
|
|
16651
|
+
if (!foundActiveLeaf && ["needs_input", "working", "blocked", "failed"].includes(residualStatus)) {
|
|
16652
|
+
currentNodeId = residualId;
|
|
16653
|
+
foundActiveLeaf = true;
|
|
16654
|
+
}
|
|
16655
|
+
}
|
|
16656
|
+
if (childStatuses.length > 0) {
|
|
16657
|
+
const representativeChildStatus = childStatuses.find(
|
|
16658
|
+
(status) => !isArtifactWorkflowNodeTerminal(status)
|
|
16659
|
+
) ?? (complete ? childStatuses.at(-1) : null);
|
|
16660
|
+
if (representativeChildStatus) {
|
|
16661
|
+
nodesById[id].status = representativeChildStatus;
|
|
16662
|
+
}
|
|
16663
|
+
nodesById[id].availability = "readonly";
|
|
16664
|
+
}
|
|
16665
|
+
if (!foundActiveLeaf && relationshipChildrenInSection.length === 0 && ["needs_input", "working", "blocked", "failed"].includes(sectionStatus)) {
|
|
16666
|
+
currentNodeId = id;
|
|
16667
|
+
foundActiveLeaf = true;
|
|
16668
|
+
}
|
|
16669
|
+
}
|
|
16670
|
+
const transitionsAreGatedByForm = (foundIncompleteSection || foundActiveLeaf) && !TERMINAL_ARTIFACT_STATUSES.has(artifact.status);
|
|
16671
|
+
for (const step of stateTransitionSteps(artifact)) {
|
|
16672
|
+
if (!step.userVisible) continue;
|
|
16673
|
+
hasVisibleTransition = true;
|
|
16674
|
+
const id = `${artifact.artifactId}:transition:${stableToken(step.transition)}`;
|
|
16675
|
+
const rawStatus = transitionNodeStatus(artifact, step);
|
|
16676
|
+
const status = isTerminalWorkflowStepStatus(rawStatus) ? rawStatus : transitionsAreGatedByForm || transitionHasActiveStep ? "upcoming" : firstTransitionStatus(artifact, rawStatus);
|
|
16677
|
+
projectedTransitionStatuses.push(status);
|
|
16678
|
+
if (!isTerminalWorkflowStepStatus(status)) {
|
|
16679
|
+
transitionHasActiveStep = true;
|
|
16680
|
+
}
|
|
16681
|
+
const blocker = step.blockers[0];
|
|
16682
|
+
nodesById[id] = {
|
|
16683
|
+
id,
|
|
16684
|
+
artifactId: artifact.artifactId,
|
|
16685
|
+
parentId: transitionGroupLabel ? transitionGroupId : operationId2,
|
|
16686
|
+
childIds: [],
|
|
16687
|
+
kind: "transition",
|
|
16688
|
+
label: step.label,
|
|
16689
|
+
description: step.description,
|
|
16690
|
+
status,
|
|
16691
|
+
availability: status === "completed" ? "readonly" : status === "upcoming" ? "unavailable" : "available",
|
|
16692
|
+
operationPhase: step.status === "needs_other_user" ? "waiting_for_approval" : status === "working" ? operationPhase(artifact) : null,
|
|
16693
|
+
operationDetail: text(record(record(artifact.metadata)?.execution)?.message) || null,
|
|
16694
|
+
recap: status === "completed" ? { summary: `${step.label} completed`, items: [] } : null,
|
|
16695
|
+
attention: status === "failed" || status === "blocked" ? {
|
|
16696
|
+
title: text(blocker?.label) || `${step.label} needs attention`,
|
|
16697
|
+
detail: text(blocker?.detail) || text(blocker?.description) || null,
|
|
16698
|
+
retryable: status === "failed"
|
|
16699
|
+
} : null,
|
|
16700
|
+
startedAt: status === "working" ? artifact.executedAt || artifact.updatedAt : null,
|
|
16701
|
+
completedAt: status === "completed" ? artifact.updatedAt : null
|
|
16702
|
+
};
|
|
16703
|
+
transitionNodeIds.push(id);
|
|
16704
|
+
if (!currentNodeId && !["completed", "upcoming", "skipped", "canceled"].includes(status)) {
|
|
16705
|
+
currentNodeId = id;
|
|
16706
|
+
}
|
|
16707
|
+
}
|
|
16708
|
+
if (transitionNodeIds.length) {
|
|
16709
|
+
const transitionNodes = transitionNodeIds.map((id) => nodesById[id]).filter((node) => Boolean(node));
|
|
16710
|
+
if (transitionGroupLabel) {
|
|
16711
|
+
const groupStatus = workflowGroupStatus(transitionNodes);
|
|
16712
|
+
const activeTransition = transitionNodes.find(
|
|
16713
|
+
(node) => ["current", "needs_input", "working", "blocked", "failed"].includes(
|
|
16714
|
+
node.status
|
|
16715
|
+
)
|
|
16716
|
+
);
|
|
16717
|
+
nodesById[transitionGroupId] = {
|
|
16718
|
+
id: transitionGroupId,
|
|
16719
|
+
artifactId: artifact.artifactId,
|
|
16720
|
+
parentId: operationId2,
|
|
16721
|
+
childIds: transitionNodeIds,
|
|
16722
|
+
kind: "group",
|
|
16723
|
+
label: transitionGroupLabel,
|
|
16724
|
+
description: null,
|
|
16725
|
+
status: groupStatus,
|
|
16726
|
+
availability: groupStatus === "upcoming" ? "unavailable" : groupStatus === "completed" ? "readonly" : "available",
|
|
16727
|
+
operationPhase: activeTransition?.operationPhase || null,
|
|
16728
|
+
startedAt: activeTransition?.startedAt || null,
|
|
16729
|
+
completedAt: groupStatus === "completed" ? transitionNodes.at(-1)?.completedAt || artifact.updatedAt : null
|
|
16730
|
+
};
|
|
16731
|
+
sectionNodeIds.push(transitionGroupId);
|
|
16732
|
+
} else {
|
|
16733
|
+
sectionNodeIds.push(...transitionNodeIds);
|
|
16734
|
+
}
|
|
16735
|
+
}
|
|
16736
|
+
const projectedOperationStatus = operationStatus(
|
|
16737
|
+
artifact,
|
|
16738
|
+
projectedTransitionStatuses
|
|
16739
|
+
);
|
|
16740
|
+
if (projectedOperationStatus === "completed") {
|
|
16741
|
+
for (const transitionNodeId of transitionNodeIds) {
|
|
16742
|
+
const transition = nodesById[transitionNodeId];
|
|
16743
|
+
if (transition?.kind === "transition" && transition.status === "completed") {
|
|
16744
|
+
transition.completionState = "graph_propagated";
|
|
16745
|
+
}
|
|
16746
|
+
}
|
|
16747
|
+
}
|
|
16748
|
+
const phase = operationPhase(artifact);
|
|
16749
|
+
const activeDescendantStatus = currentNodeId ? nodesById[currentNodeId]?.status : null;
|
|
16750
|
+
const finalStatus = activeDescendantStatus && !isTerminalWorkflowStepStatus(activeDescendantStatus) ? activeDescendantStatus : projectedOperationStatus;
|
|
16751
|
+
const validationStatus = currentNodeId ? "upcoming" : projectedOperationStatus === "upcoming" ? "current" : projectedOperationStatus;
|
|
16752
|
+
nodesById[validationId] = {
|
|
16753
|
+
id: validationId,
|
|
16754
|
+
artifactId: artifact.artifactId,
|
|
16755
|
+
parentId: operationId2,
|
|
16756
|
+
childIds: [],
|
|
16757
|
+
kind: "operation",
|
|
16758
|
+
label: operationLabel(artifact),
|
|
16759
|
+
description: artifact.description || null,
|
|
16760
|
+
status: validationStatus,
|
|
16761
|
+
availability: validationStatus === "upcoming" ? "unavailable" : validationStatus === "completed" ? "readonly" : "available",
|
|
16762
|
+
operationPhase: phase,
|
|
16763
|
+
completionState: projectedOperationStatus === "completed" ? "graph_propagated" : phase === "synchronizing" || phase === "verifying" ? "effect_applied" : null,
|
|
16764
|
+
operationDetail: text(
|
|
16765
|
+
record(record(artifact.metadata)?.execution)?.message
|
|
16766
|
+
),
|
|
16767
|
+
recap: validationStatus === "completed" ? { summary: `${artifact.label} completed`, items: [] } : null,
|
|
16768
|
+
attention: validationStatus === "failed" ? { title: `${artifact.label} failed`, retryable: true } : validationStatus === "blocked" ? {
|
|
16769
|
+
title: `${artifact.label} needs attention`,
|
|
16770
|
+
retryable: artifact.status === "stale"
|
|
16771
|
+
} : null,
|
|
16772
|
+
startedAt: artifact.executedAt || null,
|
|
16773
|
+
completedAt: artifact.completedAt || null
|
|
16774
|
+
};
|
|
16775
|
+
sectionNodeIds.push(validationId);
|
|
16776
|
+
if (!currentNodeId && !hasVisibleTransition && !["completed", "canceled"].includes(finalStatus)) {
|
|
16777
|
+
currentNodeId = validationId;
|
|
16778
|
+
}
|
|
16779
|
+
const rootStatus = currentNodeId === validationId ? nodesById[validationId].status : finalStatus;
|
|
16780
|
+
nodesById[operationId2] = {
|
|
16781
|
+
id: operationId2,
|
|
16782
|
+
artifactId: artifact.artifactId,
|
|
16783
|
+
parentId: null,
|
|
16784
|
+
childIds: sectionNodeIds,
|
|
16785
|
+
kind: "group",
|
|
16786
|
+
label: artifact.label,
|
|
16787
|
+
description: artifact.description || null,
|
|
16788
|
+
status: rootStatus,
|
|
16789
|
+
availability: rootStatus === "upcoming" ? "unavailable" : rootStatus === "completed" ? "readonly" : "available",
|
|
16790
|
+
operationPhase: null,
|
|
16791
|
+
startedAt: artifact.executedAt || null,
|
|
16792
|
+
completedAt: artifact.completedAt || null
|
|
16793
|
+
};
|
|
16794
|
+
rootNodeIds.push(operationId2);
|
|
16795
|
+
const candidateBeforeTarget = {
|
|
16796
|
+
schemaVersion: 1,
|
|
16797
|
+
revision: artifact.workflow?.revision || 1,
|
|
16798
|
+
artifactId: artifact.artifactId,
|
|
16799
|
+
rootNodeIds,
|
|
16800
|
+
nodesById,
|
|
16801
|
+
currentNodeId: null,
|
|
16802
|
+
updatedAt: now
|
|
16803
|
+
};
|
|
16804
|
+
currentNodeId = getArtifactWorkflowNavigationTarget(candidateBeforeTarget)?.id || null;
|
|
16805
|
+
const automaticTarget = currentNodeId ? nodesById[currentNodeId] || null : null;
|
|
16806
|
+
const canonicalRootStatus = automaticTarget && !isArtifactWorkflowNodeTerminal(automaticTarget) ? automaticTarget.status : projectedOperationStatus;
|
|
16807
|
+
nodesById[operationId2].status = canonicalRootStatus;
|
|
16808
|
+
nodesById[operationId2].availability = canonicalRootStatus === "upcoming" ? "unavailable" : canonicalRootStatus === "completed" ? "readonly" : "available";
|
|
16809
|
+
const candidate = {
|
|
16810
|
+
...candidateBeforeTarget,
|
|
16811
|
+
currentNodeId
|
|
16812
|
+
};
|
|
16813
|
+
if (artifact.workflow && JSON.stringify(semanticWorkflow(artifact.workflow)) !== JSON.stringify(semanticWorkflow(candidate))) {
|
|
16814
|
+
candidate.revision = artifact.workflow.revision + 1;
|
|
16815
|
+
} else if (artifact.workflow) {
|
|
16816
|
+
candidate.updatedAt = artifact.workflow.updatedAt;
|
|
16817
|
+
}
|
|
16818
|
+
return candidate;
|
|
16819
|
+
}
|
|
16820
|
+
function getCurrentArtifactWorkflowNode(workflow) {
|
|
16821
|
+
return workflow.currentNodeId ? workflow.nodesById[workflow.currentNodeId] || null : null;
|
|
16822
|
+
}
|
|
16823
|
+
function getArtifactWorkflowNodes(workflow) {
|
|
16824
|
+
const visit = (id) => {
|
|
16825
|
+
const node = workflow.nodesById[id];
|
|
16826
|
+
return node ? [node, ...node.childIds.flatMap(visit)] : [];
|
|
16827
|
+
};
|
|
16828
|
+
return workflow.rootNodeIds.flatMap(visit);
|
|
16829
|
+
}
|
|
16830
|
+
function canInspectArtifactWorkflowNode(node) {
|
|
16831
|
+
return node.childIds.length === 0 && node.availability !== "unavailable";
|
|
16832
|
+
}
|
|
16833
|
+
function assertArtifactWorkflow(workflow) {
|
|
16834
|
+
if (workflow.schemaVersion !== 1)
|
|
16835
|
+
throw new Error("Unsupported artifact workflow schema");
|
|
16836
|
+
if (!Number.isSafeInteger(workflow.revision) || workflow.revision < 1) {
|
|
16837
|
+
throw new Error("Artifact workflow revision must be a positive integer");
|
|
16838
|
+
}
|
|
16839
|
+
const visited = /* @__PURE__ */ new Set();
|
|
16840
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
16841
|
+
const nodes = [];
|
|
16842
|
+
const visit = (id, expectedParentId) => {
|
|
16843
|
+
const node = workflow.nodesById[id];
|
|
16844
|
+
if (!node) throw new Error(`Artifact workflow node ${id} does not exist`);
|
|
16845
|
+
if (visiting.has(id)) throw new Error("Artifact workflow contains a cycle");
|
|
16846
|
+
if (visited.has(id))
|
|
16847
|
+
throw new Error("Artifact workflow contains a duplicate node reference");
|
|
16848
|
+
if (node.parentId !== expectedParentId) {
|
|
16849
|
+
throw new Error(`Artifact workflow node ${id} has an invalid parent`);
|
|
16850
|
+
}
|
|
16851
|
+
visiting.add(id);
|
|
16852
|
+
nodes.push(node);
|
|
16853
|
+
node.childIds.forEach((childId) => visit(childId, id));
|
|
16854
|
+
visiting.delete(id);
|
|
16855
|
+
visited.add(id);
|
|
16856
|
+
};
|
|
16857
|
+
workflow.rootNodeIds.forEach((id) => visit(id, null));
|
|
16858
|
+
if (visited.size !== Object.keys(workflow.nodesById).length) {
|
|
16859
|
+
throw new Error("Artifact workflow contains unreachable nodes");
|
|
16860
|
+
}
|
|
16861
|
+
if (workflow.currentNodeId && !workflow.nodesById[workflow.currentNodeId]) {
|
|
16862
|
+
throw new Error("Artifact workflow current node does not exist");
|
|
16863
|
+
}
|
|
16864
|
+
const currentNode = workflow.currentNodeId ? workflow.nodesById[workflow.currentNodeId] : null;
|
|
16865
|
+
if (currentNode && currentNode.childIds.length > 0) {
|
|
16866
|
+
throw new Error("Artifact workflow current node must be actionable leaf");
|
|
16867
|
+
}
|
|
16868
|
+
const actionable = nodes.filter(
|
|
16869
|
+
(node) => isArtifactWorkflowNodeNavigableLeaf(workflow, node) && isArtifactWorkflowNodeActionable(node)
|
|
16870
|
+
);
|
|
16871
|
+
if (actionable.length > 1)
|
|
16872
|
+
throw new Error("Artifact workflow has multiple current nodes");
|
|
16873
|
+
if (actionable.length === 1 && actionable[0].id !== workflow.currentNodeId) {
|
|
16874
|
+
throw new Error("Artifact workflow current node does not own its action");
|
|
16875
|
+
}
|
|
16876
|
+
if (workflow.currentNodeId && !actionable.length && !isArtifactWorkflowNodeTerminal(currentNode)) {
|
|
16877
|
+
throw new Error("Artifact workflow current node is not actionable");
|
|
16878
|
+
}
|
|
16879
|
+
}
|
|
16880
|
+
function requireArtifactWorkflow(artifact) {
|
|
16881
|
+
if (!artifact.workflow) {
|
|
16882
|
+
throw new Error(
|
|
16883
|
+
`Artifact ${artifact.artifactId} has no canonical workflow`
|
|
16884
|
+
);
|
|
16885
|
+
}
|
|
16886
|
+
assertArtifactWorkflow(artifact.workflow);
|
|
16887
|
+
if (artifact.workflow.artifactId !== artifact.artifactId) {
|
|
16888
|
+
throw new Error("Artifact workflow belongs to a different artifact");
|
|
16889
|
+
}
|
|
16890
|
+
return artifact;
|
|
16891
|
+
}
|
|
16892
|
+
function requireArtifactWorkflowResult(result) {
|
|
16893
|
+
requireArtifactWorkflow(result.artifact);
|
|
16894
|
+
return result;
|
|
16895
|
+
}
|
|
16896
|
+
|
|
15987
16897
|
// src/client.ts
|
|
15988
16898
|
var DEFAULT_CONVERSATION_SESSION_LIST_LIMIT = 100;
|
|
15989
16899
|
var MAX_CONVERSATION_SESSION_LIST_LIMIT = 500;
|
|
@@ -16137,17 +17047,17 @@ function planRecordObjectsChunks(records, batchSize) {
|
|
|
16137
17047
|
}
|
|
16138
17048
|
return plans;
|
|
16139
17049
|
}
|
|
16140
|
-
function preserveRecordObjectRealId(
|
|
16141
|
-
const realId =
|
|
17050
|
+
function preserveRecordObjectRealId(record2) {
|
|
17051
|
+
const realId = record2.id.trim();
|
|
16142
17052
|
if (!realId) {
|
|
16143
|
-
return
|
|
17053
|
+
return record2;
|
|
16144
17054
|
}
|
|
16145
|
-
const fields =
|
|
17055
|
+
const fields = record2.fields || {};
|
|
16146
17056
|
if (typeof fields.real_id === "string" && fields.real_id.trim()) {
|
|
16147
|
-
return
|
|
17057
|
+
return record2;
|
|
16148
17058
|
}
|
|
16149
17059
|
return {
|
|
16150
|
-
...
|
|
17060
|
+
...record2,
|
|
16151
17061
|
fields: {
|
|
16152
17062
|
...fields,
|
|
16153
17063
|
real_id: realId
|
|
@@ -16479,7 +17389,7 @@ var Environment = class _Environment {
|
|
|
16479
17389
|
}
|
|
16480
17390
|
get data() {
|
|
16481
17391
|
return {
|
|
16482
|
-
record: async (
|
|
17392
|
+
record: async (record2) => this.recordObject(record2),
|
|
16483
17393
|
recordMany: async (records, options) => this.recordObjects(records, options),
|
|
16484
17394
|
import: async (records, options) => this.enqueueRecordImport(records, options),
|
|
16485
17395
|
listImports: async (status) => this.listRecordImports(status),
|
|
@@ -17827,6 +18737,7 @@ var EnvironmentSession = class extends Session {
|
|
|
17827
18737
|
sessionDataHeaders;
|
|
17828
18738
|
beforeMutationSend;
|
|
17829
18739
|
heartbeatTimer = null;
|
|
18740
|
+
heartbeatProbeInFlight = false;
|
|
17830
18741
|
/** The last known graph container status, updated by checkReadiness(). */
|
|
17831
18742
|
graphContainerStatus = null;
|
|
17832
18743
|
constructor(client, environment, clientId, options = {}) {
|
|
@@ -17846,16 +18757,34 @@ var EnvironmentSession = class extends Session {
|
|
|
17846
18757
|
* an application RPC may be delayed by Durable Object work even while the
|
|
17847
18758
|
* underlying WebSocket is healthy.
|
|
17848
18759
|
*/
|
|
17849
|
-
startHeartbeat() {
|
|
18760
|
+
startHeartbeat(options = {}) {
|
|
17850
18761
|
if (this.heartbeatTimer) return;
|
|
17851
|
-
|
|
17852
|
-
|
|
17853
|
-
|
|
17854
|
-
|
|
17855
|
-
|
|
17856
|
-
|
|
17857
|
-
|
|
17858
|
-
|
|
18762
|
+
const probeServer = options.probeServer === true;
|
|
18763
|
+
this.heartbeatTimer = setInterval(
|
|
18764
|
+
() => {
|
|
18765
|
+
if (!this.client.isTransportOpen()) return;
|
|
18766
|
+
if (probeServer) {
|
|
18767
|
+
if (this.heartbeatProbeInFlight) return;
|
|
18768
|
+
if (this.client.hasPendingRpcRequests()) return;
|
|
18769
|
+
if (this.client.hasRecentInboundActivity(1e4)) return;
|
|
18770
|
+
this.heartbeatProbeInFlight = true;
|
|
18771
|
+
void this.client.call("client.heartbeat", {}).catch((error) => {
|
|
18772
|
+
if (this.client.isTransportOpen()) {
|
|
18773
|
+
this.client.reportTransportFailure(error);
|
|
18774
|
+
}
|
|
18775
|
+
}).finally(() => {
|
|
18776
|
+
this.heartbeatProbeInFlight = false;
|
|
18777
|
+
});
|
|
18778
|
+
return;
|
|
18779
|
+
}
|
|
18780
|
+
if (this.client.hasRecentInboundActivity(3e4)) return;
|
|
18781
|
+
if (this.client.hasRecentlyPendingRpcPeriod(6e4)) return;
|
|
18782
|
+
this.client.reportTransportFailure(
|
|
18783
|
+
new Error("No server activity received for 30 seconds")
|
|
18784
|
+
);
|
|
18785
|
+
},
|
|
18786
|
+
probeServer ? 1e4 : 5e3
|
|
18787
|
+
);
|
|
17859
18788
|
this.heartbeatTimer.unref?.();
|
|
17860
18789
|
}
|
|
17861
18790
|
stopHeartbeat() {
|
|
@@ -17863,10 +18792,15 @@ var EnvironmentSession = class extends Session {
|
|
|
17863
18792
|
clearInterval(this.heartbeatTimer);
|
|
17864
18793
|
this.heartbeatTimer = null;
|
|
17865
18794
|
}
|
|
18795
|
+
this.heartbeatProbeInFlight = false;
|
|
17866
18796
|
}
|
|
17867
18797
|
async hello() {
|
|
17868
18798
|
const result = await super.hello();
|
|
17869
|
-
|
|
18799
|
+
if (result.features?.serverHeartbeat === false) {
|
|
18800
|
+
this.startHeartbeat({ probeServer: true });
|
|
18801
|
+
} else {
|
|
18802
|
+
this.startHeartbeat();
|
|
18803
|
+
}
|
|
17870
18804
|
return result;
|
|
17871
18805
|
}
|
|
17872
18806
|
get environmentId() {
|
|
@@ -18001,13 +18935,13 @@ var EnvironmentSession = class extends Session {
|
|
|
18001
18935
|
input.operationId,
|
|
18002
18936
|
"operationId"
|
|
18003
18937
|
);
|
|
18004
|
-
const
|
|
18938
|
+
const text2 = requiredAssistantReplyString(input.text, "text");
|
|
18005
18939
|
return this.sessionDataRequest(
|
|
18006
18940
|
"/assistant-replies",
|
|
18007
18941
|
void 0,
|
|
18008
18942
|
{
|
|
18009
18943
|
method: "POST",
|
|
18010
|
-
body: { id, operationId: operationId2, text }
|
|
18944
|
+
body: { id, operationId: operationId2, text: text2 }
|
|
18011
18945
|
}
|
|
18012
18946
|
);
|
|
18013
18947
|
}
|
|
@@ -18052,7 +18986,10 @@ var EnvironmentSession = class extends Session {
|
|
|
18052
18986
|
queryOptions.targetId = options.target.id;
|
|
18053
18987
|
delete queryOptions.target;
|
|
18054
18988
|
}
|
|
18055
|
-
return this.sessionDataRequest("/artifacts", queryOptions)
|
|
18989
|
+
return this.sessionDataRequest("/artifacts", queryOptions).then((page) => ({
|
|
18990
|
+
...page,
|
|
18991
|
+
items: page.items.map(requireArtifactWorkflow)
|
|
18992
|
+
}));
|
|
18056
18993
|
},
|
|
18057
18994
|
listForLatestJob: (options = {}) => this.artifacts.list({
|
|
18058
18995
|
...options,
|
|
@@ -18065,7 +19002,7 @@ var EnvironmentSession = class extends Session {
|
|
|
18065
19002
|
// `cache: no-store`; this also bypasses intermediaries that ignore
|
|
18066
19003
|
// the Fetch cache directive for an otherwise identical GET URL.
|
|
18067
19004
|
{ _granularLiveRead: Date.now() }
|
|
18068
|
-
),
|
|
19005
|
+
).then(requireArtifactWorkflow),
|
|
18069
19006
|
create: (artifact) => this.sessionDataRequest(
|
|
18070
19007
|
"/artifacts",
|
|
18071
19008
|
void 0,
|
|
@@ -18073,7 +19010,7 @@ var EnvironmentSession = class extends Session {
|
|
|
18073
19010
|
method: "POST",
|
|
18074
19011
|
body: artifact
|
|
18075
19012
|
}
|
|
18076
|
-
),
|
|
19013
|
+
).then(requireArtifactWorkflow),
|
|
18077
19014
|
acceptSuggestion: (sequence) => this.sessionDataRequest(
|
|
18078
19015
|
"/artifacts/suggestions/accept",
|
|
18079
19016
|
void 0,
|
|
@@ -18081,7 +19018,7 @@ var EnvironmentSession = class extends Session {
|
|
|
18081
19018
|
method: "POST",
|
|
18082
19019
|
body: { sequence }
|
|
18083
19020
|
}
|
|
18084
|
-
),
|
|
19021
|
+
).then(requireArtifactWorkflow),
|
|
18085
19022
|
updateInputs: (artifactId, patch) => this.sessionDataRequest(
|
|
18086
19023
|
`/artifacts/${encodeURIComponent(artifactId)}`,
|
|
18087
19024
|
void 0,
|
|
@@ -18089,7 +19026,7 @@ var EnvironmentSession = class extends Session {
|
|
|
18089
19026
|
method: "PATCH",
|
|
18090
19027
|
body: patch
|
|
18091
19028
|
}
|
|
18092
|
-
),
|
|
19029
|
+
).then(requireArtifactWorkflow),
|
|
18093
19030
|
relationshipOptions: (artifactId, input) => this.sessionDataRequest(
|
|
18094
19031
|
`/artifacts/${encodeURIComponent(artifactId)}/relationship-options`,
|
|
18095
19032
|
void 0,
|
|
@@ -18099,27 +19036,27 @@ var EnvironmentSession = class extends Session {
|
|
|
18099
19036
|
`/artifacts/${encodeURIComponent(artifactId)}/relationship-create`,
|
|
18100
19037
|
void 0,
|
|
18101
19038
|
{ method: "POST", body: input }
|
|
18102
|
-
),
|
|
19039
|
+
).then(requireArtifactWorkflow),
|
|
18103
19040
|
validate: (artifactId) => this.sessionDataRequest(
|
|
18104
19041
|
`/artifacts/${encodeURIComponent(artifactId)}/validate`,
|
|
18105
19042
|
void 0,
|
|
18106
19043
|
{ method: "POST" }
|
|
18107
|
-
),
|
|
19044
|
+
).then(requireArtifactWorkflowResult),
|
|
18108
19045
|
execute: (artifactId, options) => this.sessionDataRequest(
|
|
18109
19046
|
`/artifacts/${encodeURIComponent(artifactId)}/execute`,
|
|
18110
19047
|
void 0,
|
|
18111
19048
|
{ method: "POST", body: options }
|
|
18112
|
-
),
|
|
19049
|
+
).then(requireArtifactWorkflowResult),
|
|
18113
19050
|
approve: (artifactId, options) => this.sessionDataRequest(
|
|
18114
19051
|
`/artifacts/${encodeURIComponent(artifactId)}/approve`,
|
|
18115
19052
|
void 0,
|
|
18116
19053
|
{ method: "POST", body: options }
|
|
18117
|
-
),
|
|
19054
|
+
).then(requireArtifactWorkflowResult),
|
|
18118
19055
|
cancel: (artifactId) => this.sessionDataRequest(
|
|
18119
19056
|
`/artifacts/${encodeURIComponent(artifactId)}/cancel`,
|
|
18120
19057
|
void 0,
|
|
18121
19058
|
{ method: "POST" }
|
|
18122
|
-
)
|
|
19059
|
+
).then(requireArtifactWorkflow)
|
|
18123
19060
|
};
|
|
18124
19061
|
}
|
|
18125
19062
|
get manualActions() {
|
|
@@ -20107,13 +21044,13 @@ var Granular = class _Granular {
|
|
|
20107
21044
|
* Permission Profile management for sandboxes
|
|
20108
21045
|
*/
|
|
20109
21046
|
get permissionProfiles() {
|
|
20110
|
-
const profileSourceFromRecord = (
|
|
20111
|
-
const profile =
|
|
21047
|
+
const profileSourceFromRecord = (record2) => {
|
|
21048
|
+
const profile = record2.profile || record2.rules || {};
|
|
20112
21049
|
return {
|
|
20113
21050
|
...profile,
|
|
20114
21051
|
schemaVersion: profile.schemaVersion || 1,
|
|
20115
|
-
name: profile.name ||
|
|
20116
|
-
description: profile.description ||
|
|
21052
|
+
name: profile.name || record2.name,
|
|
21053
|
+
description: profile.description || record2.description
|
|
20117
21054
|
};
|
|
20118
21055
|
};
|
|
20119
21056
|
return {
|
|
@@ -20696,18 +21633,18 @@ function stableValue(value) {
|
|
|
20696
21633
|
function stableJson(value) {
|
|
20697
21634
|
return JSON.stringify(stableValue(value));
|
|
20698
21635
|
}
|
|
20699
|
-
function recordKey(
|
|
20700
|
-
return `${
|
|
21636
|
+
function recordKey(record2) {
|
|
21637
|
+
return `${record2.className}\0${record2.id}`;
|
|
20701
21638
|
}
|
|
20702
21639
|
function recordReference(className, id) {
|
|
20703
21640
|
return { className, id };
|
|
20704
21641
|
}
|
|
20705
21642
|
function changedRecordSnapshots(beforeRecords, afterRecords) {
|
|
20706
21643
|
const before = new Map(
|
|
20707
|
-
beforeRecords.map((
|
|
21644
|
+
beforeRecords.map((record2) => [recordKey(record2), record2])
|
|
20708
21645
|
);
|
|
20709
21646
|
const after = new Map(
|
|
20710
|
-
afterRecords.map((
|
|
21647
|
+
afterRecords.map((record2) => [recordKey(record2), record2])
|
|
20711
21648
|
);
|
|
20712
21649
|
const changedKeys = /* @__PURE__ */ new Set();
|
|
20713
21650
|
for (const key of /* @__PURE__ */ new Set([...before.keys(), ...after.keys()])) {
|
|
@@ -20717,10 +21654,10 @@ function changedRecordSnapshots(beforeRecords, afterRecords) {
|
|
|
20717
21654
|
}
|
|
20718
21655
|
return {
|
|
20719
21656
|
beforeRecords: beforeRecords.filter(
|
|
20720
|
-
(
|
|
21657
|
+
(record2) => changedKeys.has(recordKey(record2))
|
|
20721
21658
|
),
|
|
20722
21659
|
afterRecords: afterRecords.filter(
|
|
20723
|
-
(
|
|
21660
|
+
(record2) => changedKeys.has(recordKey(record2))
|
|
20724
21661
|
)
|
|
20725
21662
|
};
|
|
20726
21663
|
}
|
|
@@ -20769,35 +21706,35 @@ function changedObjectProjection(before, after) {
|
|
|
20769
21706
|
}
|
|
20770
21707
|
function projectionChanges(input) {
|
|
20771
21708
|
const before = new Map(
|
|
20772
|
-
input.beforeRecords.map((
|
|
21709
|
+
input.beforeRecords.map((record2) => [recordKey(record2), record2])
|
|
20773
21710
|
);
|
|
20774
21711
|
const after = new Map(
|
|
20775
|
-
input.afterRecords.map((
|
|
21712
|
+
input.afterRecords.map((record2) => [recordKey(record2), record2])
|
|
20776
21713
|
);
|
|
20777
21714
|
const targets = relationshipTargets(input.manifest);
|
|
20778
21715
|
const changes = [];
|
|
20779
|
-
for (const
|
|
20780
|
-
const previous = before.get(recordKey(
|
|
20781
|
-
const objectChange = changedObjectProjection(previous,
|
|
21716
|
+
for (const record2 of input.afterRecords) {
|
|
21717
|
+
const previous = before.get(recordKey(record2));
|
|
21718
|
+
const objectChange = changedObjectProjection(previous, record2);
|
|
20782
21719
|
if (objectChange) changes.push(objectChange);
|
|
20783
21720
|
const relationshipNames = /* @__PURE__ */ new Set([
|
|
20784
21721
|
...Object.keys(previous?.relationships || {}),
|
|
20785
|
-
...Object.keys(
|
|
21722
|
+
...Object.keys(record2.relationships || {})
|
|
20786
21723
|
]);
|
|
20787
21724
|
for (const relationshipName of [...relationshipNames].sort()) {
|
|
20788
21725
|
const target = targets.get(
|
|
20789
|
-
`${
|
|
21726
|
+
`${record2.className}\0${relationshipName}`
|
|
20790
21727
|
);
|
|
20791
21728
|
if (!target) {
|
|
20792
21729
|
throw new Error(
|
|
20793
|
-
`No ontology relationship target is declared for ${
|
|
21730
|
+
`No ontology relationship target is declared for ${record2.className}.${relationshipName}`
|
|
20794
21731
|
);
|
|
20795
21732
|
}
|
|
20796
21733
|
const previousIds = new Set(
|
|
20797
21734
|
asIds(previous?.relationships?.[relationshipName])
|
|
20798
21735
|
);
|
|
20799
21736
|
const currentIds = new Set(
|
|
20800
|
-
asIds(
|
|
21737
|
+
asIds(record2.relationships?.[relationshipName])
|
|
20801
21738
|
);
|
|
20802
21739
|
for (const id of [...previousIds].sort()) {
|
|
20803
21740
|
if (currentIds.has(id)) continue;
|
|
@@ -20805,7 +21742,7 @@ function projectionChanges(input) {
|
|
|
20805
21742
|
kind: "relationship",
|
|
20806
21743
|
operation: "disconnected",
|
|
20807
21744
|
relationship: relationshipName,
|
|
20808
|
-
from: recordReference(
|
|
21745
|
+
from: recordReference(record2.className, record2.id),
|
|
20809
21746
|
to: recordReference(target.className, id)
|
|
20810
21747
|
});
|
|
20811
21748
|
}
|
|
@@ -20815,37 +21752,37 @@ function projectionChanges(input) {
|
|
|
20815
21752
|
kind: "relationship",
|
|
20816
21753
|
operation: "connected",
|
|
20817
21754
|
relationship: relationshipName,
|
|
20818
|
-
from: recordReference(
|
|
21755
|
+
from: recordReference(record2.className, record2.id),
|
|
20819
21756
|
to: recordReference(target.className, id)
|
|
20820
21757
|
});
|
|
20821
21758
|
}
|
|
20822
21759
|
}
|
|
20823
21760
|
const machines = /* @__PURE__ */ new Set([
|
|
20824
21761
|
...Object.keys(previous?.states || {}),
|
|
20825
|
-
...Object.keys(
|
|
21762
|
+
...Object.keys(record2.states || {})
|
|
20826
21763
|
]);
|
|
20827
21764
|
for (const machine of [...machines].sort()) {
|
|
20828
|
-
const next =
|
|
21765
|
+
const next = record2.states?.[machine];
|
|
20829
21766
|
if (next === void 0) continue;
|
|
20830
21767
|
const prior = previous?.states?.[machine];
|
|
20831
21768
|
if (prior !== void 0 && stateName(prior) === stateName(next)) continue;
|
|
20832
|
-
if (input.transition && input.transition.className ===
|
|
21769
|
+
if (input.transition && input.transition.className === record2.className && input.transition.objectId === record2.id && input.transition.machine === machine) {
|
|
20833
21770
|
continue;
|
|
20834
21771
|
}
|
|
20835
21772
|
changes.push({
|
|
20836
21773
|
kind: "state_observation",
|
|
20837
|
-
target: recordReference(
|
|
21774
|
+
target: recordReference(record2.className, record2.id),
|
|
20838
21775
|
machine,
|
|
20839
21776
|
state: stateName(next)
|
|
20840
21777
|
});
|
|
20841
21778
|
}
|
|
20842
21779
|
}
|
|
20843
|
-
for (const
|
|
20844
|
-
if (after.has(recordKey(
|
|
21780
|
+
for (const record2 of input.beforeRecords) {
|
|
21781
|
+
if (after.has(recordKey(record2))) continue;
|
|
20845
21782
|
changes.push({
|
|
20846
21783
|
kind: "object",
|
|
20847
21784
|
operation: "deleted",
|
|
20848
|
-
target: recordReference(
|
|
21785
|
+
target: recordReference(record2.className, record2.id)
|
|
20849
21786
|
});
|
|
20850
21787
|
}
|
|
20851
21788
|
return changes;
|
|
@@ -20890,7 +21827,7 @@ function transitionOutcome(transition, afterRecords) {
|
|
|
20890
21827
|
throw new Error("A transition commit has no authored transition context.");
|
|
20891
21828
|
}
|
|
20892
21829
|
const target = afterRecords.find(
|
|
20893
|
-
(
|
|
21830
|
+
(record2) => record2.className === transition.className && record2.id === transition.objectId
|
|
20894
21831
|
);
|
|
20895
21832
|
const observed = target?.states?.[transition.machine];
|
|
20896
21833
|
if (!observed) {
|
|
@@ -20936,7 +21873,8 @@ function projectRecordSnapshotMutation(input) {
|
|
|
20936
21873
|
const base = {
|
|
20937
21874
|
source: {
|
|
20938
21875
|
reference: input.source.reference,
|
|
20939
|
-
...input.source.version ? { version: input.source.version } : {}
|
|
21876
|
+
...input.source.version ? { version: input.source.version } : {},
|
|
21877
|
+
...input.source.versionScope ? { versionScope: input.source.versionScope } : {}
|
|
20940
21878
|
},
|
|
20941
21879
|
...target ? { primaryTarget: target } : {},
|
|
20942
21880
|
changes,
|
|
@@ -21107,29 +22045,29 @@ function requireRecord(value, context) {
|
|
|
21107
22045
|
}
|
|
21108
22046
|
return value;
|
|
21109
22047
|
}
|
|
21110
|
-
function requiredString(
|
|
21111
|
-
const value =
|
|
22048
|
+
function requiredString(record2, key, context) {
|
|
22049
|
+
const value = record2[key];
|
|
21112
22050
|
if (typeof value !== "string" || !value.trim()) {
|
|
21113
22051
|
throw new Error(`${context}.${key} must be a non-empty string.`);
|
|
21114
22052
|
}
|
|
21115
22053
|
return value;
|
|
21116
22054
|
}
|
|
21117
|
-
function requiredNumber(
|
|
21118
|
-
const value =
|
|
22055
|
+
function requiredNumber(record2, key, context) {
|
|
22056
|
+
const value = record2[key];
|
|
21119
22057
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
21120
22058
|
throw new Error(`${context}.${key} must be a finite number.`);
|
|
21121
22059
|
}
|
|
21122
22060
|
return value;
|
|
21123
22061
|
}
|
|
21124
|
-
function requiredStringArray(
|
|
21125
|
-
const value =
|
|
22062
|
+
function requiredStringArray(record2, key, context) {
|
|
22063
|
+
const value = record2[key];
|
|
21126
22064
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
|
|
21127
22065
|
throw new Error(`${context}.${key} must be an array of non-empty strings.`);
|
|
21128
22066
|
}
|
|
21129
22067
|
return [...value];
|
|
21130
22068
|
}
|
|
21131
|
-
function requiredNumberRecord(
|
|
21132
|
-
const value = requireRecord(
|
|
22069
|
+
function requiredNumberRecord(record2, key, context) {
|
|
22070
|
+
const value = requireRecord(record2[key], `${context}.${key}`);
|
|
21133
22071
|
const output = {};
|
|
21134
22072
|
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
21135
22073
|
if (typeof entryValue !== "number" || !Number.isFinite(entryValue) || entryValue < 0 || entryValue > 1) {
|
|
@@ -21142,22 +22080,22 @@ function requiredNumberRecord(record, key, context) {
|
|
|
21142
22080
|
return output;
|
|
21143
22081
|
}
|
|
21144
22082
|
function validateHarnessTemplateManifest(value, context = "HarnessTemplateManifest") {
|
|
21145
|
-
const
|
|
21146
|
-
const status = requiredString(
|
|
22083
|
+
const record2 = requireRecord(value, context);
|
|
22084
|
+
const status = requiredString(record2, "status", context);
|
|
21147
22085
|
if (!HARNESS_TEMPLATE_STATUSES.includes(status)) {
|
|
21148
22086
|
throw new Error(
|
|
21149
22087
|
`${context}.status must be one of ${HARNESS_TEMPLATE_STATUSES.join(", ")}.`
|
|
21150
22088
|
);
|
|
21151
22089
|
}
|
|
21152
|
-
const createdAt = requiredString(
|
|
22090
|
+
const createdAt = requiredString(record2, "createdAt", context);
|
|
21153
22091
|
if (Number.isNaN(Date.parse(createdAt))) {
|
|
21154
22092
|
throw new Error(`${context}.createdAt must be an ISO timestamp.`);
|
|
21155
22093
|
}
|
|
21156
22094
|
const compatibility = requireRecord(
|
|
21157
|
-
|
|
22095
|
+
record2.compatibility,
|
|
21158
22096
|
`${context}.compatibility`
|
|
21159
22097
|
);
|
|
21160
|
-
const evalGates = requireRecord(
|
|
22098
|
+
const evalGates = requireRecord(record2.evalGates, `${context}.evalGates`);
|
|
21161
22099
|
const maxRegressionPct = requiredNumber(
|
|
21162
22100
|
evalGates,
|
|
21163
22101
|
"maxRegressionPct",
|
|
@@ -21169,23 +22107,23 @@ function validateHarnessTemplateManifest(value, context = "HarnessTemplateManife
|
|
|
21169
22107
|
);
|
|
21170
22108
|
}
|
|
21171
22109
|
return {
|
|
21172
|
-
id: requiredString(
|
|
21173
|
-
version: requiredString(
|
|
22110
|
+
id: requiredString(record2, "id", context),
|
|
22111
|
+
version: requiredString(record2, "version", context),
|
|
21174
22112
|
status,
|
|
21175
|
-
owner: requiredString(
|
|
22113
|
+
owner: requiredString(record2, "owner", context),
|
|
21176
22114
|
createdAt,
|
|
21177
|
-
changelog: requiredString(
|
|
21178
|
-
promptBuilder: requiredString(
|
|
21179
|
-
continuationBuilder: requiredString(
|
|
22115
|
+
changelog: requiredString(record2, "changelog", context),
|
|
22116
|
+
promptBuilder: requiredString(record2, "promptBuilder", context),
|
|
22117
|
+
continuationBuilder: requiredString(record2, "continuationBuilder", context),
|
|
21180
22118
|
modelOutputInstruction: requiredString(
|
|
21181
|
-
|
|
22119
|
+
record2,
|
|
21182
22120
|
"modelOutputInstruction",
|
|
21183
22121
|
context
|
|
21184
22122
|
),
|
|
21185
|
-
codeReviewPolicy: requiredString(
|
|
21186
|
-
defaultModel: requiredString(
|
|
21187
|
-
modelMatrix: requiredStringArray(
|
|
21188
|
-
temperature: requiredNumber(
|
|
22123
|
+
codeReviewPolicy: requiredString(record2, "codeReviewPolicy", context),
|
|
22124
|
+
defaultModel: requiredString(record2, "defaultModel", context),
|
|
22125
|
+
modelMatrix: requiredStringArray(record2, "modelMatrix", context),
|
|
22126
|
+
temperature: requiredNumber(record2, "temperature", context),
|
|
21189
22127
|
compatibility: {
|
|
21190
22128
|
minSdkVersion: requiredString(
|
|
21191
22129
|
compatibility,
|
|
@@ -21239,27 +22177,27 @@ var DEFAULT_LOW_SIGNAL_REASONING_LINES = [
|
|
|
21239
22177
|
function parseReasoningCommentLine(line, options = {}) {
|
|
21240
22178
|
const trimmed = line.trimStart();
|
|
21241
22179
|
if (!trimmed.startsWith("//")) return null;
|
|
21242
|
-
const
|
|
21243
|
-
if (!
|
|
22180
|
+
const text2 = trimmed.replace(/^\/\/\s?/, "").trim();
|
|
22181
|
+
if (!text2) return { kind: "ignored" };
|
|
21244
22182
|
const ignoredDirectives = options.ignoredCommentDirectives || DEFAULT_IGNORED_REASONING_COMMENT_DIRECTIVES;
|
|
21245
|
-
if (ignoredDirectives.some((pattern) => pattern.test(
|
|
22183
|
+
if (ignoredDirectives.some((pattern) => pattern.test(text2))) {
|
|
21246
22184
|
return { kind: "ignored" };
|
|
21247
22185
|
}
|
|
21248
22186
|
const lowSignalLines = options.lowSignalReasoningLines || DEFAULT_LOW_SIGNAL_REASONING_LINES;
|
|
21249
|
-
if (lowSignalLines.some((pattern) => pattern.test(
|
|
22187
|
+
if (lowSignalLines.some((pattern) => pattern.test(text2))) {
|
|
21250
22188
|
return { kind: "ignored" };
|
|
21251
22189
|
}
|
|
21252
|
-
return { kind: "reasoning", text };
|
|
22190
|
+
return { kind: "reasoning", text: text2 };
|
|
21253
22191
|
}
|
|
21254
22192
|
function consumeGranularReasoningTraceChunk(buffer, chunk, options = {}) {
|
|
21255
|
-
let
|
|
22193
|
+
let text2 = buffer + chunk;
|
|
21256
22194
|
let visibleText = "";
|
|
21257
22195
|
const reasoningLines = [];
|
|
21258
22196
|
while (true) {
|
|
21259
|
-
const newlineIndex =
|
|
22197
|
+
const newlineIndex = text2.indexOf("\n");
|
|
21260
22198
|
if (newlineIndex === -1) break;
|
|
21261
|
-
const rawLine =
|
|
21262
|
-
|
|
22199
|
+
const rawLine = text2.slice(0, newlineIndex);
|
|
22200
|
+
text2 = text2.slice(newlineIndex + 1);
|
|
21263
22201
|
const comment = parseReasoningCommentLine(
|
|
21264
22202
|
rawLine.replace(/\r$/, ""),
|
|
21265
22203
|
options
|
|
@@ -21273,19 +22211,19 @@ function consumeGranularReasoningTraceChunk(buffer, chunk, options = {}) {
|
|
|
21273
22211
|
`;
|
|
21274
22212
|
}
|
|
21275
22213
|
}
|
|
21276
|
-
if (options.final &&
|
|
21277
|
-
const comment = parseReasoningCommentLine(
|
|
22214
|
+
if (options.final && text2.length > 0) {
|
|
22215
|
+
const comment = parseReasoningCommentLine(text2.replace(/\r$/, ""), options);
|
|
21278
22216
|
if (comment?.kind === "reasoning") {
|
|
21279
22217
|
reasoningLines.push(comment.text);
|
|
21280
|
-
|
|
22218
|
+
text2 = "";
|
|
21281
22219
|
} else if (comment?.kind === "ignored") {
|
|
21282
|
-
|
|
22220
|
+
text2 = "";
|
|
21283
22221
|
} else {
|
|
21284
|
-
visibleText +=
|
|
21285
|
-
|
|
22222
|
+
visibleText += text2;
|
|
22223
|
+
text2 = "";
|
|
21286
22224
|
}
|
|
21287
22225
|
}
|
|
21288
|
-
return { buffer:
|
|
22226
|
+
return { buffer: text2, visibleText, reasoningLines };
|
|
21289
22227
|
}
|
|
21290
22228
|
function consumeGranularReasoningOnlyChunk(buffer, chunk, options = {}) {
|
|
21291
22229
|
const result = consumeGranularReasoningTraceChunk(buffer, chunk, options);
|
|
@@ -21294,8 +22232,8 @@ function consumeGranularReasoningOnlyChunk(buffer, chunk, options = {}) {
|
|
|
21294
22232
|
reasoningLines: result.reasoningLines
|
|
21295
22233
|
};
|
|
21296
22234
|
}
|
|
21297
|
-
function stripGranularReasoningTrace(
|
|
21298
|
-
return consumeGranularReasoningTraceChunk("",
|
|
22235
|
+
function stripGranularReasoningTrace(text2, options = {}) {
|
|
22236
|
+
return consumeGranularReasoningTraceChunk("", text2, {
|
|
21299
22237
|
...options,
|
|
21300
22238
|
final: true
|
|
21301
22239
|
}).visibleText.trim();
|
|
@@ -21330,8 +22268,8 @@ function stableStringify(value) {
|
|
|
21330
22268
|
if (Array.isArray(value)) {
|
|
21331
22269
|
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
21332
22270
|
}
|
|
21333
|
-
const
|
|
21334
|
-
return `{${Object.keys(
|
|
22271
|
+
const record2 = value;
|
|
22272
|
+
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record2[key])}`).join(",")}}`;
|
|
21335
22273
|
}
|
|
21336
22274
|
function renderConstBlock(name, value) {
|
|
21337
22275
|
return `const ${name} = ${JSON.stringify(value, null, 2)} as const;`;
|
|
@@ -21927,9 +22865,9 @@ function getLatestClosure(liveDoc) {
|
|
|
21927
22865
|
}
|
|
21928
22866
|
const closures = [];
|
|
21929
22867
|
for (const [closureId, value] of Object.entries(closuresById)) {
|
|
21930
|
-
const
|
|
21931
|
-
if (!
|
|
21932
|
-
closures.push({ ...
|
|
22868
|
+
const record2 = asRecord4(value);
|
|
22869
|
+
if (!record2) continue;
|
|
22870
|
+
closures.push({ ...record2, closureId });
|
|
21933
22871
|
}
|
|
21934
22872
|
closures.sort(
|
|
21935
22873
|
(left, right) => (Number(right.createdAt) || 0) - (Number(left.createdAt) || 0)
|
|
@@ -21967,9 +22905,9 @@ function getJobRecords(liveDoc) {
|
|
|
21967
22905
|
const jobsById = asRecord4(asRecord4(liveDoc?.jobs)?.byId) || {};
|
|
21968
22906
|
const jobs = [];
|
|
21969
22907
|
for (const [jobId, value] of Object.entries(jobsById)) {
|
|
21970
|
-
const
|
|
21971
|
-
if (!
|
|
21972
|
-
jobs.push({ ...
|
|
22908
|
+
const record2 = asRecord4(value);
|
|
22909
|
+
if (!record2) continue;
|
|
22910
|
+
jobs.push({ ...record2, jobId });
|
|
21973
22911
|
}
|
|
21974
22912
|
jobs.sort(
|
|
21975
22913
|
(left, right) => getJobTimestamp(right) - getJobTimestamp(left)
|
|
@@ -22155,8 +23093,8 @@ function hasOpenPrompt(liveDoc, pendingPrompts) {
|
|
|
22155
23093
|
const prompts = asRecord4(asRecord4(job)?.prompts);
|
|
22156
23094
|
if (!prompts) continue;
|
|
22157
23095
|
for (const prompt of Object.values(prompts)) {
|
|
22158
|
-
const
|
|
22159
|
-
if (
|
|
23096
|
+
const record2 = asRecord4(prompt);
|
|
23097
|
+
if (record2?.status === "open") return true;
|
|
22160
23098
|
}
|
|
22161
23099
|
}
|
|
22162
23100
|
return false;
|
|
@@ -22215,13 +23153,13 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
22215
23153
|
title: typeof decision.title === "string" && decision.title.trim() ? decision.title.trim() : "Decision",
|
|
22216
23154
|
status,
|
|
22217
23155
|
candidates: status === "open" ? asArray(decision.candidates).slice(0, 5).map((candidate) => {
|
|
22218
|
-
const
|
|
22219
|
-
if (!
|
|
23156
|
+
const record2 = asRecord4(candidate);
|
|
23157
|
+
if (!record2) return null;
|
|
22220
23158
|
return {
|
|
22221
|
-
id: typeof
|
|
22222
|
-
label: typeof
|
|
22223
|
-
description: typeof
|
|
22224
|
-
metadata: asRecord4(
|
|
23159
|
+
id: typeof record2.id === "string" ? record2.id : "unknown",
|
|
23160
|
+
label: typeof record2.label === "string" && record2.label.trim() ? record2.label.trim() : null,
|
|
23161
|
+
description: typeof record2.description === "string" && record2.description.trim() ? record2.description.trim() : null,
|
|
23162
|
+
metadata: asRecord4(record2.metadata)
|
|
22225
23163
|
};
|
|
22226
23164
|
}).filter(Boolean) : [],
|
|
22227
23165
|
selected: status === "open" ? null : {
|
|
@@ -22856,11 +23794,11 @@ function normalizeJsonSchema(value) {
|
|
|
22856
23794
|
return asRecord4(value);
|
|
22857
23795
|
}
|
|
22858
23796
|
function jsonSchemaTypeName(schema) {
|
|
22859
|
-
const
|
|
22860
|
-
if (!
|
|
22861
|
-
const type =
|
|
22862
|
-
if (
|
|
22863
|
-
if (
|
|
23797
|
+
const record2 = normalizeJsonSchema(schema);
|
|
23798
|
+
if (!record2) return "unknown";
|
|
23799
|
+
const type = record2.type;
|
|
23800
|
+
if (record2.format === "date-time") return "date-time";
|
|
23801
|
+
if (record2.format === "date" || type === "date" || Array.isArray(type) && type.includes("date")) {
|
|
22864
23802
|
return "date";
|
|
22865
23803
|
}
|
|
22866
23804
|
if (typeof type === "string") {
|
|
@@ -22871,12 +23809,12 @@ function jsonSchemaTypeName(schema) {
|
|
|
22871
23809
|
return "unknown";
|
|
22872
23810
|
}
|
|
22873
23811
|
function summarizeObjectSchema(schema) {
|
|
22874
|
-
const
|
|
22875
|
-
const properties = asRecord4(
|
|
23812
|
+
const record2 = normalizeJsonSchema(schema);
|
|
23813
|
+
const properties = asRecord4(record2?.properties);
|
|
22876
23814
|
if (!properties || Object.keys(properties).length === 0) {
|
|
22877
|
-
return
|
|
23815
|
+
return record2 ? "{}" : null;
|
|
22878
23816
|
}
|
|
22879
|
-
const required = new Set(asArray(
|
|
23817
|
+
const required = new Set(asArray(record2?.required));
|
|
22880
23818
|
const fields = Object.entries(properties).slice(0, 8).map(([name, property]) => {
|
|
22881
23819
|
const marker = required.has(name) ? "*" : "?";
|
|
22882
23820
|
return `${name}${marker}: ${jsonSchemaTypeName(property)}`;
|
|
@@ -23365,6 +24303,10 @@ ${actionIndex}
|
|
|
23365
24303
|
- Use suggestions when the user asks "what can I do next?", asks for options, or gives an unclear intent. Prefer 2 to 5 concrete suggestions and keep text short.
|
|
23366
24304
|
- Opening a prepared action does not execute the underlying mutation. Use \`.open()\` only when the user asks to prepare, review, show, or edit an action before running it, when a new record must be prepared, or when a reviewable form must collect missing editable inputs. Prefill only grounded values and leave unknown fields empty.
|
|
23367
24305
|
- For creation inputs, use the declared action schema and its field descriptions as the mapping authority. Copy every compatible value explicitly present in the current request, conversation, selected/saved object, file, fresh read, or declared ontology default, including values for fields with arbitrary names. Omit only values for which that context provides no evidence.
|
|
24306
|
+
- Preserve explicit qualifiers from the user's requested object identity, including quantities, product names, and named organizational scope. Do not shorten a title in a way that drops those qualifiers when they distinguish what is being created.
|
|
24307
|
+
- A contextual or ontology default may fill a value only when the user supplied no conflicting intent for that semantic role. If the user names a team, owner, account, location, or other scope that cannot be grounded, leave that relationship unresolved; never substitute the current actor's default or another convenient visible record.
|
|
24308
|
+
- A missing or inaccessible required relationship is not a reason to replace a reviewable action with a lookup-failure reply. Call the reviewable action with every grounded non-relationship value, omit the unresolved relationship, and let the artifact collect it from the user. This applies even when the user explicitly named the unavailable relationship.
|
|
24309
|
+
- Choose enum values from the request's meaning and the ontology-authored option semantics. Do not choose an enum merely because it makes an available default relationship, budget, policy, or downstream option compatible. If no enum is semantically supported, leave it unresolved or ask.
|
|
23368
24310
|
- Never fill an input because of its field name, a regular expression or other string pattern, its primitive type, a schema minimum, an example value, or the first enum option. If the evidence is ambiguous, leave the field unresolved or ask the user.
|
|
23369
24311
|
- When the user explicitly commands an existing-record mutation such as approve, reject, block, route, send, or update, and one visible domain action uniquely matches, call that domain action directly. Do not substitute a state-handle \`.open()\` artifact for execution. If runtime policy requires confirmation, invoke the action once and let the runtime pause and resume that same invocation.
|
|
23370
24312
|
- When a grounded related/context record can satisfy the prepared action through declared relationships, use those relationships to fill required relationship inputs before opening or updating the action. If a required relationship remains empty, continue through declared relationship chains from the grounded object when the next hop can fill that slot. Do not only save the context record in memory while leaving derivable relationship slots blank.
|
|
@@ -23618,10 +24560,10 @@ function responseTextFromFeedItems(feedItems, jobId) {
|
|
|
23618
24560
|
if (item.kind !== "message" || item.payload.role !== "assistant" || item.source?.jobId !== jobId || item.sequence <= latestSequence) {
|
|
23619
24561
|
continue;
|
|
23620
24562
|
}
|
|
23621
|
-
const
|
|
23622
|
-
if (!
|
|
24563
|
+
const text2 = item.payload.text.trim();
|
|
24564
|
+
if (!text2) continue;
|
|
23623
24565
|
latestSequence = item.sequence;
|
|
23624
|
-
latestText =
|
|
24566
|
+
latestText = text2;
|
|
23625
24567
|
}
|
|
23626
24568
|
return latestText;
|
|
23627
24569
|
}
|
|
@@ -23636,39 +24578,39 @@ function pushStringArray(target, value) {
|
|
|
23636
24578
|
pushString(target, item);
|
|
23637
24579
|
}
|
|
23638
24580
|
}
|
|
23639
|
-
function collectReferencesFromRecord(
|
|
24581
|
+
function collectReferencesFromRecord(record2, refs) {
|
|
23640
24582
|
for (const key of ENTRY_KEY_CANDIDATES)
|
|
23641
|
-
pushString(refs.entryPaths,
|
|
24583
|
+
pushString(refs.entryPaths, record2[key]);
|
|
23642
24584
|
for (const key of ENTRY_ARRAY_KEY_CANDIDATES)
|
|
23643
|
-
pushStringArray(refs.entryPaths,
|
|
24585
|
+
pushStringArray(refs.entryPaths, record2[key]);
|
|
23644
24586
|
for (const key of LIST_KEY_CANDIDATES)
|
|
23645
|
-
pushString(refs.listNames,
|
|
24587
|
+
pushString(refs.listNames, record2[key]);
|
|
23646
24588
|
for (const key of LIST_ARRAY_KEY_CANDIDATES)
|
|
23647
|
-
pushStringArray(refs.listNames,
|
|
24589
|
+
pushStringArray(refs.listNames, record2[key]);
|
|
23648
24590
|
for (const key of VARIABLE_KEY_CANDIDATES)
|
|
23649
|
-
pushString(refs.variableNames,
|
|
24591
|
+
pushString(refs.variableNames, record2[key]);
|
|
23650
24592
|
for (const key of VARIABLE_ARRAY_KEY_CANDIDATES)
|
|
23651
|
-
pushStringArray(refs.variableNames,
|
|
24593
|
+
pushStringArray(refs.variableNames, record2[key]);
|
|
23652
24594
|
}
|
|
23653
|
-
function stringValue(
|
|
24595
|
+
function stringValue(record2, keys) {
|
|
23654
24596
|
for (const key of keys) {
|
|
23655
|
-
const value =
|
|
24597
|
+
const value = record2[key];
|
|
23656
24598
|
if (typeof value === "string" && value.trim()) {
|
|
23657
24599
|
return value.trim();
|
|
23658
24600
|
}
|
|
23659
24601
|
}
|
|
23660
24602
|
return null;
|
|
23661
24603
|
}
|
|
23662
|
-
function findEntryPathForRecord(
|
|
23663
|
-
const directPath = stringValue(
|
|
24604
|
+
function findEntryPathForRecord(record2, heap) {
|
|
24605
|
+
const directPath = stringValue(record2, ["entryPath", "path"]);
|
|
23664
24606
|
if (directPath && heap.entriesByPath?.[directPath]) {
|
|
23665
24607
|
return directPath;
|
|
23666
24608
|
}
|
|
23667
|
-
const id = stringValue(
|
|
24609
|
+
const id = stringValue(record2, ["id", "_id", "recordId", "objectId"]);
|
|
23668
24610
|
if (!id) {
|
|
23669
24611
|
return null;
|
|
23670
24612
|
}
|
|
23671
|
-
const className = stringValue(
|
|
24613
|
+
const className = stringValue(record2, [
|
|
23672
24614
|
"className",
|
|
23673
24615
|
"_className",
|
|
23674
24616
|
"__className",
|
|
@@ -23702,17 +24644,17 @@ function scanForHeapReferences(value, heap, refs, depth = 0, seen = /* @__PURE__
|
|
|
23702
24644
|
}
|
|
23703
24645
|
return;
|
|
23704
24646
|
}
|
|
23705
|
-
const
|
|
23706
|
-
if (!
|
|
24647
|
+
const record2 = asRecord5(value);
|
|
24648
|
+
if (!record2) return;
|
|
23707
24649
|
seen.add(value);
|
|
23708
|
-
const entryPath = findEntryPathForRecord(
|
|
24650
|
+
const entryPath = findEntryPathForRecord(record2, heap);
|
|
23709
24651
|
if (entryPath) refs.entryPaths.add(entryPath);
|
|
23710
|
-
collectReferencesFromRecord(
|
|
24652
|
+
collectReferencesFromRecord(record2, refs);
|
|
23711
24653
|
for (const key of UI_CONTAINER_KEYS) {
|
|
23712
|
-
const nested = asRecord5(
|
|
24654
|
+
const nested = asRecord5(record2[key]);
|
|
23713
24655
|
if (nested) collectReferencesFromRecord(nested, refs);
|
|
23714
24656
|
}
|
|
23715
|
-
for (const nested of Object.values(
|
|
24657
|
+
for (const nested of Object.values(record2).slice(0, 24)) {
|
|
23716
24658
|
scanForHeapReferences(nested, heap, refs, depth + 1, seen);
|
|
23717
24659
|
}
|
|
23718
24660
|
}
|
|
@@ -23861,8 +24803,8 @@ var OPENAI_MODEL_PRICING_USD_PER_MILLION = {
|
|
|
23861
24803
|
function asRecord6(value) {
|
|
23862
24804
|
return value && typeof value === "object" ? value : null;
|
|
23863
24805
|
}
|
|
23864
|
-
function numberField(
|
|
23865
|
-
const value =
|
|
24806
|
+
function numberField(record2, key) {
|
|
24807
|
+
const value = record2?.[key];
|
|
23866
24808
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
23867
24809
|
}
|
|
23868
24810
|
function microsPerMillion(usdPerMillion) {
|
|
@@ -23966,6 +24908,216 @@ function calculateOpenAITokenSpend(model, rawUsage) {
|
|
|
23966
24908
|
};
|
|
23967
24909
|
}
|
|
23968
24910
|
|
|
24911
|
+
// src/artifact-surface.ts
|
|
24912
|
+
function operationNode(workflow) {
|
|
24913
|
+
return getArtifactWorkflowNodes(workflow).find(
|
|
24914
|
+
(node) => node.kind === "operation"
|
|
24915
|
+
) || null;
|
|
24916
|
+
}
|
|
24917
|
+
function operationStatusLabel(phase) {
|
|
24918
|
+
if (phase === "reviewing") return "Preparing";
|
|
24919
|
+
if (phase === "sending") return "In progress";
|
|
24920
|
+
if (phase === "synchronizing") return "Saving";
|
|
24921
|
+
if (phase === "verifying") return "Verifying";
|
|
24922
|
+
if (phase === "waiting_for_approval") return "Awaiting approval";
|
|
24923
|
+
if (phase === "completed") return "Completed";
|
|
24924
|
+
if (phase === "failed") return "Failed";
|
|
24925
|
+
return null;
|
|
24926
|
+
}
|
|
24927
|
+
function action(id, label, tone, disabled, disabledReason = null) {
|
|
24928
|
+
return { id, label, tone, disabled, disabledReason };
|
|
24929
|
+
}
|
|
24930
|
+
function navigationIsUseful(workflow) {
|
|
24931
|
+
const nodes = getArtifactWorkflowNodes(workflow).filter(
|
|
24932
|
+
(node) => node.kind !== "operation" && node.kind !== "group"
|
|
24933
|
+
);
|
|
24934
|
+
return nodes.length > 1 || nodes.some((node) => node.kind === "child_artifact");
|
|
24935
|
+
}
|
|
24936
|
+
function inputNode(workflow, activeEditorNodeId) {
|
|
24937
|
+
if (activeEditorNodeId) {
|
|
24938
|
+
const active = workflow.nodesById[activeEditorNodeId];
|
|
24939
|
+
if (active && (active.kind === "input" || active.kind === "relationship")) {
|
|
24940
|
+
return active;
|
|
24941
|
+
}
|
|
24942
|
+
}
|
|
24943
|
+
const current = getCurrentArtifactWorkflowNode(workflow);
|
|
24944
|
+
return current?.kind === "input" || current?.kind === "relationship" ? current : null;
|
|
24945
|
+
}
|
|
24946
|
+
function selectArtifactSurface(artifact, context = {}) {
|
|
24947
|
+
const workflow = artifact.workflow || projectArtifactWorkflow(artifact);
|
|
24948
|
+
const operation = operationNode(workflow);
|
|
24949
|
+
const workflowStatus = operation?.status || null;
|
|
24950
|
+
const terminal = workflowStatus === "completed" || workflowStatus === "canceled";
|
|
24951
|
+
const requestedEditorNodeId = terminal ? null : context.activeEditorNodeId || null;
|
|
24952
|
+
const current = getCurrentArtifactWorkflowNode(workflow);
|
|
24953
|
+
const activeInput = inputNode(workflow, requestedEditorNodeId);
|
|
24954
|
+
const mutationsDisabled = context.mutationsDisabled === true;
|
|
24955
|
+
const busy = Boolean(context.busyAction);
|
|
24956
|
+
const disabledReason = mutationsDisabled ? "Reconnect to continue." : busy ? "This action is already in progress." : null;
|
|
24957
|
+
const actionDisabled = Boolean(disabledReason);
|
|
24958
|
+
const transportStatus = context.transportStatus || "connected";
|
|
24959
|
+
let kind;
|
|
24960
|
+
if (artifact.status === "completed" && workflowStatus === "completed") {
|
|
24961
|
+
kind = "result";
|
|
24962
|
+
} else if (artifact.status === "completed" && workflowStatus === "failed") {
|
|
24963
|
+
kind = "failure";
|
|
24964
|
+
} else if (artifact.status === "completed" && workflowStatus === "working") {
|
|
24965
|
+
kind = "executing";
|
|
24966
|
+
} else if (artifact.status === "completed" && workflowStatus && workflowStatus !== "canceled") {
|
|
24967
|
+
kind = "blocked";
|
|
24968
|
+
} else if (artifact.status === "completed") kind = "result";
|
|
24969
|
+
else if (artifact.status === "canceled") kind = "canceled";
|
|
24970
|
+
else if (artifact.status === "stale") kind = "stale";
|
|
24971
|
+
else if (artifact.status === "partially_completed") kind = "partial";
|
|
24972
|
+
else if (artifact.status === "failed" || context.directError)
|
|
24973
|
+
kind = "failure";
|
|
24974
|
+
else if (artifact.status === "blocked") kind = "blocked";
|
|
24975
|
+
else if (artifact.status === "awaiting_human") kind = "approval";
|
|
24976
|
+
else if (artifact.status === "running" || busy) kind = "executing";
|
|
24977
|
+
else if (requestedEditorNodeId || artifact.status === "draft" || artifact.status === "needs_edit") {
|
|
24978
|
+
kind = "input";
|
|
24979
|
+
} else {
|
|
24980
|
+
kind = "review";
|
|
24981
|
+
}
|
|
24982
|
+
let title = artifact.label;
|
|
24983
|
+
let description = artifact.description || null;
|
|
24984
|
+
let statusLabel = null;
|
|
24985
|
+
let primaryAction = null;
|
|
24986
|
+
let secondaryActions = [];
|
|
24987
|
+
if (kind === "input") {
|
|
24988
|
+
title = activeInput?.label || artifact.label;
|
|
24989
|
+
description = activeInput?.description || artifact.description || null;
|
|
24990
|
+
statusLabel = activeInput?.status === "needs_input" ? "Needs input" : null;
|
|
24991
|
+
primaryAction = action(
|
|
24992
|
+
"continue",
|
|
24993
|
+
"Continue",
|
|
24994
|
+
"primary",
|
|
24995
|
+
actionDisabled,
|
|
24996
|
+
disabledReason
|
|
24997
|
+
);
|
|
24998
|
+
} else if (kind === "review") {
|
|
24999
|
+
title = artifact.label;
|
|
25000
|
+
description = artifact.description || operation?.description || null;
|
|
25001
|
+
primaryAction = action(
|
|
25002
|
+
"execute",
|
|
25003
|
+
operation?.label || "Continue",
|
|
25004
|
+
"primary",
|
|
25005
|
+
actionDisabled || context.canExecute === false,
|
|
25006
|
+
disabledReason
|
|
25007
|
+
);
|
|
25008
|
+
if (context.canEdit) {
|
|
25009
|
+
secondaryActions = [
|
|
25010
|
+
action(
|
|
25011
|
+
"edit",
|
|
25012
|
+
"Edit details",
|
|
25013
|
+
"secondary",
|
|
25014
|
+
actionDisabled,
|
|
25015
|
+
disabledReason
|
|
25016
|
+
)
|
|
25017
|
+
];
|
|
25018
|
+
}
|
|
25019
|
+
} else if (kind === "executing") {
|
|
25020
|
+
title = operation?.operationDetail || operation?.label || artifact.label;
|
|
25021
|
+
description = operation?.operationDetail ? artifact.label : null;
|
|
25022
|
+
statusLabel = operationStatusLabel(operation?.operationPhase) || "In progress";
|
|
25023
|
+
} else if (kind === "approval") {
|
|
25024
|
+
title = operation?.attention?.title || operation?.label || artifact.label;
|
|
25025
|
+
description = operation?.attention?.detail || operation?.description || null;
|
|
25026
|
+
statusLabel = "Awaiting approval";
|
|
25027
|
+
if (context.canApprove) {
|
|
25028
|
+
primaryAction = action(
|
|
25029
|
+
"approve",
|
|
25030
|
+
"Approve",
|
|
25031
|
+
"primary",
|
|
25032
|
+
actionDisabled,
|
|
25033
|
+
disabledReason
|
|
25034
|
+
);
|
|
25035
|
+
secondaryActions = [
|
|
25036
|
+
action(
|
|
25037
|
+
"decline",
|
|
25038
|
+
"Decline",
|
|
25039
|
+
"secondary",
|
|
25040
|
+
actionDisabled,
|
|
25041
|
+
disabledReason
|
|
25042
|
+
)
|
|
25043
|
+
];
|
|
25044
|
+
}
|
|
25045
|
+
} else if (kind === "failure" || kind === "blocked") {
|
|
25046
|
+
const attention = current?.attention || operation?.attention;
|
|
25047
|
+
title = attention?.title || artifact.label;
|
|
25048
|
+
description = context.directError || attention?.detail || operation?.description || null;
|
|
25049
|
+
statusLabel = kind === "failure" ? "Failed" : "Needs attention";
|
|
25050
|
+
if (attention?.retryable) {
|
|
25051
|
+
primaryAction = action(
|
|
25052
|
+
"retry",
|
|
25053
|
+
"Retry",
|
|
25054
|
+
"primary",
|
|
25055
|
+
actionDisabled,
|
|
25056
|
+
disabledReason
|
|
25057
|
+
);
|
|
25058
|
+
} else if (context.canEdit) {
|
|
25059
|
+
primaryAction = action(
|
|
25060
|
+
"edit",
|
|
25061
|
+
"Edit details",
|
|
25062
|
+
"primary",
|
|
25063
|
+
actionDisabled,
|
|
25064
|
+
disabledReason
|
|
25065
|
+
);
|
|
25066
|
+
}
|
|
25067
|
+
} else if (kind === "partial") {
|
|
25068
|
+
title = operation?.attention?.title || artifact.label;
|
|
25069
|
+
description = operation?.attention?.detail || operation?.description || null;
|
|
25070
|
+
statusLabel = "Partially completed";
|
|
25071
|
+
primaryAction = action(
|
|
25072
|
+
"retry",
|
|
25073
|
+
"Retry unfinished work",
|
|
25074
|
+
"primary",
|
|
25075
|
+
actionDisabled,
|
|
25076
|
+
disabledReason
|
|
25077
|
+
);
|
|
25078
|
+
} else if (kind === "stale") {
|
|
25079
|
+
title = operation?.attention?.title || artifact.label;
|
|
25080
|
+
description = operation?.attention?.detail || operation?.description || null;
|
|
25081
|
+
statusLabel = "Details changed";
|
|
25082
|
+
primaryAction = action(
|
|
25083
|
+
"refresh",
|
|
25084
|
+
"Review latest details",
|
|
25085
|
+
"primary",
|
|
25086
|
+
actionDisabled,
|
|
25087
|
+
disabledReason
|
|
25088
|
+
);
|
|
25089
|
+
} else if (kind === "result") {
|
|
25090
|
+
title = artifact.label;
|
|
25091
|
+
description = operation?.recap?.summary || artifact.description || null;
|
|
25092
|
+
statusLabel = "Completed";
|
|
25093
|
+
primaryAction = action("close", "Done", "primary", false);
|
|
25094
|
+
} else {
|
|
25095
|
+
title = artifact.label;
|
|
25096
|
+
description = operation?.attention?.detail || "Nothing else will run.";
|
|
25097
|
+
statusLabel = "Canceled";
|
|
25098
|
+
primaryAction = action("close", "Done", "primary", false);
|
|
25099
|
+
}
|
|
25100
|
+
const activeNodeId = kind === "input" ? activeInput?.id || workflow.currentNodeId : workflow.currentNodeId;
|
|
25101
|
+
const announcement = [statusLabel, title, description].filter((value) => Boolean(value)).join(". ");
|
|
25102
|
+
return {
|
|
25103
|
+
artifactId: artifact.artifactId,
|
|
25104
|
+
revision: workflow.revision,
|
|
25105
|
+
updatedAt: artifact.updatedAt,
|
|
25106
|
+
kind,
|
|
25107
|
+
title,
|
|
25108
|
+
description,
|
|
25109
|
+
statusLabel,
|
|
25110
|
+
announcement,
|
|
25111
|
+
workflow,
|
|
25112
|
+
activeNodeId,
|
|
25113
|
+
operationNodeId: operation?.id || null,
|
|
25114
|
+
showNavigation: navigationIsUseful(workflow),
|
|
25115
|
+
primaryAction,
|
|
25116
|
+
secondaryActions,
|
|
25117
|
+
transportStatus
|
|
25118
|
+
};
|
|
25119
|
+
}
|
|
25120
|
+
|
|
23969
25121
|
exports.Environment = Environment;
|
|
23970
25122
|
exports.EnvironmentSession = EnvironmentSession;
|
|
23971
25123
|
exports.GRANULAR_FEED_DIAGNOSTIC_EVENT = GRANULAR_FEED_DIAGNOSTIC_EVENT;
|
|
@@ -23975,6 +25127,7 @@ exports.OntologyHandle = OntologyHandle;
|
|
|
23975
25127
|
exports.Session = Session;
|
|
23976
25128
|
exports.SessionFeedController = SessionFeedController;
|
|
23977
25129
|
exports.WSClient = WSClient;
|
|
25130
|
+
exports.assertArtifactWorkflow = assertArtifactWorkflow;
|
|
23978
25131
|
exports.buildContinuationInstruction = buildContinuationInstruction;
|
|
23979
25132
|
exports.buildContinuationInstructionFromTemplate = buildContinuationInstructionFromTemplate;
|
|
23980
25133
|
exports.buildGranularAgentCheckpointBlock = buildGranularAgentCheckpointBlock;
|
|
@@ -23995,6 +25148,7 @@ exports.buildOpenAISpendEventId = buildOpenAISpendEventId;
|
|
|
23995
25148
|
exports.buildSessionTranscript = buildSessionTranscript;
|
|
23996
25149
|
exports.buildSessionTranscriptFromFeedItems = buildSessionTranscriptFromFeedItems;
|
|
23997
25150
|
exports.calculateOpenAITokenSpend = calculateOpenAITokenSpend;
|
|
25151
|
+
exports.canInspectArtifactWorkflowNode = canInspectArtifactWorkflowNode;
|
|
23998
25152
|
exports.canonicalizeCommitValue = canonicalizeCommitValue;
|
|
23999
25153
|
exports.changedRecordSnapshots = changedRecordSnapshots;
|
|
24000
25154
|
exports.consumeGranularReasoningOnlyChunk = consumeGranularReasoningOnlyChunk;
|
|
@@ -24012,6 +25166,10 @@ exports.environmentSetupProgressFromResponse = environmentSetupProgressFromRespo
|
|
|
24012
25166
|
exports.evaluateContinuation = evaluateContinuation;
|
|
24013
25167
|
exports.evaluateValidationRule = evaluateValidationRule;
|
|
24014
25168
|
exports.extractPromptTokens = extractPromptTokens;
|
|
25169
|
+
exports.getArtifactWorkflowNavigationLeaves = getArtifactWorkflowNavigationLeaves;
|
|
25170
|
+
exports.getArtifactWorkflowNavigationTarget = getArtifactWorkflowNavigationTarget;
|
|
25171
|
+
exports.getArtifactWorkflowNodes = getArtifactWorkflowNodes;
|
|
25172
|
+
exports.getCurrentArtifactWorkflowNode = getCurrentArtifactWorkflowNode;
|
|
24015
25173
|
exports.getCurrentClosureId = getCurrentClosureId;
|
|
24016
25174
|
exports.getDefaultHarnessTemplateId = getDefaultHarnessTemplateId;
|
|
24017
25175
|
exports.getExclusivePromptTarget = getExclusivePromptTarget;
|
|
@@ -24020,6 +25178,8 @@ exports.hasCanonicalSessionFeedActivation = hasCanonicalSessionFeedActivation;
|
|
|
24020
25178
|
exports.hasOpenPrompt = hasOpenPrompt;
|
|
24021
25179
|
exports.hashHarnessTemplateValue = hashHarnessTemplateValue;
|
|
24022
25180
|
exports.invokeRegisteredEffect = invokeRegisteredEffect;
|
|
25181
|
+
exports.isArtifactWorkflowNodeNavigableLeaf = isArtifactWorkflowNodeNavigableLeaf;
|
|
25182
|
+
exports.isArtifactWorkflowNodeTerminal = isArtifactWorkflowNodeTerminal;
|
|
24023
25183
|
exports.isCanonicalSessionFeedDocument = isCanonicalSessionFeedDocument;
|
|
24024
25184
|
exports.isGraphQLMutationDocument = isGraphQLMutationDocument;
|
|
24025
25185
|
exports.isLocalApiUrl = isLocalApiUrl;
|
|
@@ -24036,6 +25196,7 @@ exports.normalizePromptText = normalizePromptText;
|
|
|
24036
25196
|
exports.normalizePromptType = normalizePromptType;
|
|
24037
25197
|
exports.orderTransientFeedItems = orderTransientFeedItems;
|
|
24038
25198
|
exports.pollEnvironmentSetup = pollEnvironmentSetup;
|
|
25199
|
+
exports.projectArtifactWorkflow = projectArtifactWorkflow;
|
|
24039
25200
|
exports.projectConversationReferentFocus = projectConversationReferentFocus;
|
|
24040
25201
|
exports.projectConversationReferentSummary = projectConversationReferentSummary;
|
|
24041
25202
|
exports.projectHeapSummary = projectHeapSummary;
|
|
@@ -24048,6 +25209,8 @@ exports.readSessionFeedSnapshot = readSessionFeedSnapshot;
|
|
|
24048
25209
|
exports.recordOpenAIUsageSpend = recordOpenAIUsageSpend;
|
|
24049
25210
|
exports.renderContinuationInstructionFromTemplate = renderContinuationInstructionFromTemplate;
|
|
24050
25211
|
exports.renderGranularAgentSystemPromptFromTemplate = renderGranularAgentSystemPromptFromTemplate;
|
|
25212
|
+
exports.requireArtifactWorkflow = requireArtifactWorkflow;
|
|
25213
|
+
exports.requireArtifactWorkflowResult = requireArtifactWorkflowResult;
|
|
24051
25214
|
exports.resolveApiUrl = resolveApiUrl;
|
|
24052
25215
|
exports.resolveAuthTokenForApiUrl = resolveAuthTokenForApiUrl;
|
|
24053
25216
|
exports.resolveHarnessTemplate = resolveHarnessTemplate;
|
|
@@ -24055,6 +25218,7 @@ exports.resolveJobPresentation = resolveJobPresentation;
|
|
|
24055
25218
|
exports.resolvePromptAnswer = resolvePromptAnswer;
|
|
24056
25219
|
exports.reviewGeneratedJobCode = reviewGeneratedJobCode;
|
|
24057
25220
|
exports.scorePromptChoiceMatch = scorePromptChoiceMatch;
|
|
25221
|
+
exports.selectArtifactSurface = selectArtifactSurface;
|
|
24058
25222
|
exports.stripGranularReasoningTrace = stripGranularReasoningTrace;
|
|
24059
25223
|
exports.toGranularHttpBase = toGranularHttpBase;
|
|
24060
25224
|
exports.validateHarnessTemplateManifest = validateHarnessTemplateManifest;
|