@granular-software/sdk 0.4.49 → 0.4.50
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 +1107 -103
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +1107 -103
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.d.mts +19 -2
- package/dist/agent-harness.d.ts +19 -2
- package/dist/agent-harness.js +79 -26
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +78 -27
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +1008 -66
- package/dist/{client-B-MPVvDr.d.mts → client-BbI7ThzU.d.ts} +62 -1
- package/dist/{client-zihxkDDs.d.ts → client-DaYFTHG8.d.mts} +62 -1
- package/dist/index.d.mts +104 -5
- package/dist/index.d.ts +104 -5
- package/dist/index.js +1189 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1186 -95
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-CStuOBXb.d.mts → spend-RpJikX9w.d.mts} +383 -11
- package/dist/{spend-CStuOBXb.d.ts → spend-RpJikX9w.d.ts} +383 -11
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/package.json +2 -1
package/dist/agent-evals.js
CHANGED
|
@@ -4045,6 +4045,9 @@ function rpcTimeoutMsForMethod(method) {
|
|
|
4045
4045
|
return DOMAIN_PACKAGE_RPC_TIMEOUT_MS;
|
|
4046
4046
|
case "client.heartbeat":
|
|
4047
4047
|
case "effects.publishCatalog":
|
|
4048
|
+
case "effects.resetCatalog":
|
|
4049
|
+
case "effects.addCatalog":
|
|
4050
|
+
case "effects.removeCatalog":
|
|
4048
4051
|
case "effects.refresh":
|
|
4049
4052
|
return EFFECT_CONTROL_RPC_TIMEOUT_MS;
|
|
4050
4053
|
case "harness.run":
|
|
@@ -4790,6 +4793,9 @@ function resolvePromptAnswer(prompt, answer) {
|
|
|
4790
4793
|
|
|
4791
4794
|
// src/session.ts
|
|
4792
4795
|
var PROMPT_TRANSCRIPT_APPEND_TIMEOUT_MS = 5e3;
|
|
4796
|
+
function toPascalCase(value) {
|
|
4797
|
+
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
4798
|
+
}
|
|
4793
4799
|
function withPromptTranscriptTimeout(promise) {
|
|
4794
4800
|
let timeout = null;
|
|
4795
4801
|
return Promise.race([
|
|
@@ -5352,9 +5358,7 @@ var Session = class {
|
|
|
5352
5358
|
if (classes && Object.keys(classes).length > 0) {
|
|
5353
5359
|
let docs2 = "# Domain Documentation\n\n";
|
|
5354
5360
|
docs2 += "Import concrete classes from `@granular/domain/<Class>` and global backend actions from `@granular/actions/backend`:\n\n";
|
|
5355
|
-
const classNames = Object.keys(classes).map(
|
|
5356
|
-
(c) => c.charAt(0).toUpperCase() + c.slice(1)
|
|
5357
|
-
);
|
|
5361
|
+
const classNames = Object.keys(classes).map(toPascalCase);
|
|
5358
5362
|
const globalNames = (globalTools || []).map((t) => t.name);
|
|
5359
5363
|
const importLines = [
|
|
5360
5364
|
...classNames.map(
|
|
@@ -5368,7 +5372,7 @@ ${importLines.join("\n") || "// No generated domain imports available."}
|
|
|
5368
5372
|
|
|
5369
5373
|
`;
|
|
5370
5374
|
for (const [className, cls] of Object.entries(classes)) {
|
|
5371
|
-
const TsName =
|
|
5375
|
+
const TsName = toPascalCase(className);
|
|
5372
5376
|
docs2 += `## ${TsName}
|
|
5373
5377
|
|
|
5374
5378
|
`;
|
|
@@ -6358,6 +6362,28 @@ function asString(value) {
|
|
|
6358
6362
|
function trimString(value) {
|
|
6359
6363
|
return typeof value === "string" ? value.trim() : "";
|
|
6360
6364
|
}
|
|
6365
|
+
function compactJson(value, maxLength = 320) {
|
|
6366
|
+
if (value === void 0 || value === null) return void 0;
|
|
6367
|
+
try {
|
|
6368
|
+
const json = JSON.stringify(value);
|
|
6369
|
+
if (!json || json === "undefined") return void 0;
|
|
6370
|
+
return json.length > maxLength ? `${json.slice(0, maxLength)}...` : json;
|
|
6371
|
+
} catch {
|
|
6372
|
+
return String(value);
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6375
|
+
function artifactRecordsById(liveDoc) {
|
|
6376
|
+
const artifacts = asRecord3(liveDoc?.artifacts);
|
|
6377
|
+
const byId = asRecord3(artifacts?.byId) || {};
|
|
6378
|
+
return Object.fromEntries(
|
|
6379
|
+
Object.entries(byId).map(([artifactId, value]) => {
|
|
6380
|
+
const record = asRecord3(value);
|
|
6381
|
+
return record ? [artifactId, record] : null;
|
|
6382
|
+
}).filter(
|
|
6383
|
+
(entry) => Boolean(entry)
|
|
6384
|
+
)
|
|
6385
|
+
);
|
|
6386
|
+
}
|
|
6361
6387
|
function normalizeShowRefs(value) {
|
|
6362
6388
|
const record = asRecord3(value);
|
|
6363
6389
|
if (!record) return void 0;
|
|
@@ -6374,9 +6400,31 @@ function normalizeShowRefs(value) {
|
|
|
6374
6400
|
entryPaths: normalizeRefs(record.entryPaths),
|
|
6375
6401
|
listNames: normalizeRefs(record.listNames),
|
|
6376
6402
|
variableNames: normalizeRefs(record.variableNames),
|
|
6377
|
-
fileIds: normalizeRefs(record.fileIds)
|
|
6403
|
+
fileIds: normalizeRefs(record.fileIds),
|
|
6404
|
+
sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
|
|
6405
|
+
actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
|
|
6378
6406
|
};
|
|
6379
|
-
return show.entryPaths || show.listNames || show.variableNames || show.fileIds ? show : void 0;
|
|
6407
|
+
return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions ? show : void 0;
|
|
6408
|
+
}
|
|
6409
|
+
function normalizeActionSuggestions(value) {
|
|
6410
|
+
if (!Array.isArray(value)) return void 0;
|
|
6411
|
+
const suggestions = [];
|
|
6412
|
+
for (const item of value) {
|
|
6413
|
+
const record = asRecord3(item);
|
|
6414
|
+
if (!record) continue;
|
|
6415
|
+
const label = trimString(record.label);
|
|
6416
|
+
if (!label) continue;
|
|
6417
|
+
const suggestionId = trimString(record.suggestionId) || trimString(record.id) || label;
|
|
6418
|
+
suggestions.push({
|
|
6419
|
+
suggestionId,
|
|
6420
|
+
label,
|
|
6421
|
+
...typeof record.description === "string" ? { description: record.description } : {},
|
|
6422
|
+
...asRecord3(record.artifact) ? { artifact: asRecord3(record.artifact) } : {},
|
|
6423
|
+
...asRecord3(record.target) ? { target: asRecord3(record.target) } : {},
|
|
6424
|
+
...asRecord3(record.metadata) ? { metadata: asRecord3(record.metadata) } : {}
|
|
6425
|
+
});
|
|
6426
|
+
}
|
|
6427
|
+
return suggestions.length ? suggestions : void 0;
|
|
6380
6428
|
}
|
|
6381
6429
|
function stringifyTranscriptValue(value, fallback = "") {
|
|
6382
6430
|
if (typeof value === "string") {
|
|
@@ -6396,12 +6444,139 @@ function stringifyTranscriptValue(value, fallback = "") {
|
|
|
6396
6444
|
return String(value);
|
|
6397
6445
|
}
|
|
6398
6446
|
}
|
|
6399
|
-
function
|
|
6447
|
+
function latestInputEditSummary(metadata) {
|
|
6448
|
+
const lastInputEdit = asRecord3(metadata.lastInputEdit);
|
|
6449
|
+
if (!lastInputEdit) return null;
|
|
6450
|
+
const source = asString(lastInputEdit.source) || "unknown";
|
|
6451
|
+
const actor = asString(lastInputEdit.actorSubjectId) || asString(lastInputEdit.actorPermissionProfileName) || asString(lastInputEdit.jobId) || null;
|
|
6452
|
+
const inputKeys = Array.isArray(lastInputEdit.changedInputKeys) ? lastInputEdit.changedInputKeys.filter(
|
|
6453
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6454
|
+
).slice(0, 6) : [];
|
|
6455
|
+
const relationshipKeys = Array.isArray(lastInputEdit.changedRelationshipKeys) ? lastInputEdit.changedRelationshipKeys.filter(
|
|
6456
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6457
|
+
).slice(0, 6) : [];
|
|
6458
|
+
const changed = [
|
|
6459
|
+
inputKeys.length ? `inputs=${inputKeys.join(",")}` : null,
|
|
6460
|
+
relationshipKeys.length ? `relationships=${relationshipKeys.join(",")}` : null
|
|
6461
|
+
].filter(Boolean);
|
|
6462
|
+
return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
|
|
6463
|
+
}
|
|
6464
|
+
function artifactIssueSummary(record) {
|
|
6465
|
+
const validation = asRecord3(record.validation);
|
|
6466
|
+
if (!validation) return null;
|
|
6467
|
+
const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
|
|
6468
|
+
if (issues.length > 0) {
|
|
6469
|
+
return `issues=${issues.map((issue) => {
|
|
6470
|
+
const code = asString(issue.code) || asString(issue.kind) || "issue";
|
|
6471
|
+
const path2 = asString(issue.path);
|
|
6472
|
+
const message = trimString(issue.message);
|
|
6473
|
+
return `${code}${path2 ? ` at ${path2}` : ""}${message ? ` (${message})` : ""}`;
|
|
6474
|
+
}).join("; ")}`;
|
|
6475
|
+
}
|
|
6476
|
+
const error = trimString(validation.error) || trimString(validation.reason) || trimString(validation.message);
|
|
6477
|
+
return error ? `validation=${error}` : null;
|
|
6478
|
+
}
|
|
6479
|
+
function artifactExecutionSummary(metadata) {
|
|
6480
|
+
const execution = asRecord3(metadata.execution);
|
|
6481
|
+
if (!execution) return null;
|
|
6482
|
+
const result = asRecord3(execution.result);
|
|
6483
|
+
const awaiting = asString(result?.awaiting) || asString(execution.awaiting);
|
|
6484
|
+
const pendingTransition = asString(result?.pendingTransition) || asString(execution.pendingTransition);
|
|
6485
|
+
const approval = asRecord3(result?.approval) || asRecord3(execution.approval);
|
|
6486
|
+
const approvalTarget = asString(approval?.permissionProfileName) || asString(approval?.permissionProfileId) || asString(approval?.assigneeSubjectId);
|
|
6487
|
+
const error = trimString(execution.error);
|
|
6488
|
+
const pieces = [
|
|
6489
|
+
awaiting ? `awaiting=${awaiting}` : null,
|
|
6490
|
+
pendingTransition ? `pendingTransition=${pendingTransition}` : null,
|
|
6491
|
+
approvalTarget ? `approvalTarget=${approvalTarget}` : null,
|
|
6492
|
+
error ? `executionError=${error}` : null
|
|
6493
|
+
].filter(Boolean);
|
|
6494
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6495
|
+
}
|
|
6496
|
+
function artifactStatePathSummary(metadata) {
|
|
6497
|
+
const statePlan = asRecord3(metadata.statePlan);
|
|
6498
|
+
if (!statePlan) return null;
|
|
6499
|
+
const machineName = asString(statePlan.machineName);
|
|
6500
|
+
const targetState = asString(statePlan.targetState);
|
|
6501
|
+
const objectPath = asString(statePlan.objectPath);
|
|
6502
|
+
const approvedTransitions = Array.isArray(statePlan.approvedTransitions) ? statePlan.approvedTransitions.length : 0;
|
|
6503
|
+
const approvalDecisions = Array.isArray(statePlan.approvalDecisions) ? statePlan.approvalDecisions.length : 0;
|
|
6504
|
+
const pieces = [
|
|
6505
|
+
machineName || targetState ? `statePath=${machineName || "state_machine"}${targetState ? ` -> ${targetState}` : ""}` : null,
|
|
6506
|
+
objectPath ? `objectPath=${objectPath}` : null,
|
|
6507
|
+
approvedTransitions ? `approvedTransitions=${approvedTransitions}` : null,
|
|
6508
|
+
approvalDecisions ? `approvalDecisions=${approvalDecisions}` : null
|
|
6509
|
+
].filter(Boolean);
|
|
6510
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6511
|
+
}
|
|
6512
|
+
function artifactSummaryLine(artifactId, record) {
|
|
6513
|
+
if (!record) return `- ${artifactId}: unavailable in session artifact store`;
|
|
6514
|
+
const label = trimString(record.label) || artifactId;
|
|
6515
|
+
const kind = asString(record.kind) || "artifact";
|
|
6516
|
+
const status = asString(record.status) || "unknown";
|
|
6517
|
+
const createdByJobId = asString(record.createdByJobId);
|
|
6518
|
+
const target = asRecord3(record.target);
|
|
6519
|
+
const metadata = asRecord3(record.metadata) || {};
|
|
6520
|
+
const subArtifactIds = Array.isArray(record.subArtifactIds) ? record.subArtifactIds.filter(
|
|
6521
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
6522
|
+
).slice(0, 8) : [];
|
|
6523
|
+
const relationships = compactJson(record.relationships, 220);
|
|
6524
|
+
const pieces = [
|
|
6525
|
+
`kind=${kind}`,
|
|
6526
|
+
`status=${status}`,
|
|
6527
|
+
createdByJobId ? `createdByJob=${createdByJobId}` : null,
|
|
6528
|
+
target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
|
|
6529
|
+
artifactStatePathSummary(metadata),
|
|
6530
|
+
artifactExecutionSummary(metadata),
|
|
6531
|
+
artifactIssueSummary(record),
|
|
6532
|
+
latestInputEditSummary(metadata),
|
|
6533
|
+
subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
|
|
6534
|
+
relationships ? `relationships=${relationships}` : null
|
|
6535
|
+
].filter(Boolean);
|
|
6536
|
+
return `- ${artifactId}: ${label}${pieces.length ? `; ${pieces.join("; ")}` : ""}`;
|
|
6537
|
+
}
|
|
6538
|
+
function buildArtifactHistory(show, artifactsById) {
|
|
6400
6539
|
if (!show) return void 0;
|
|
6401
|
-
|
|
6540
|
+
const artifactIds = show.sessionArtifactIds || [];
|
|
6541
|
+
const actionSuggestions = show.actionSuggestions || [];
|
|
6542
|
+
if (artifactIds.length === 0 && actionSuggestions.length === 0) {
|
|
6543
|
+
return `[Agent message]
|
|
6402
6544
|
${stringifyTranscriptValue({ show }, "")}`;
|
|
6545
|
+
}
|
|
6546
|
+
const lines = artifactIds.slice(0, 8).map(
|
|
6547
|
+
(artifactId) => artifactSummaryLine(artifactId, artifactsById?.[artifactId])
|
|
6548
|
+
);
|
|
6549
|
+
if (artifactIds.length > 8) {
|
|
6550
|
+
lines.push(`- ${artifactIds.length - 8} more artifacts omitted`);
|
|
6551
|
+
}
|
|
6552
|
+
if (actionSuggestions.length > 0) {
|
|
6553
|
+
if (artifactIds.length > 0) lines.push("[Agent suggested actions]");
|
|
6554
|
+
for (const suggestion of actionSuggestions.slice(0, 8)) {
|
|
6555
|
+
lines.push(
|
|
6556
|
+
`- ${suggestion.label}${suggestion.description ? `; ${suggestion.description}` : ""}`
|
|
6557
|
+
);
|
|
6558
|
+
}
|
|
6559
|
+
if (actionSuggestions.length > 8) {
|
|
6560
|
+
lines.push(`- ${actionSuggestions.length - 8} more suggestions omitted`);
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
const otherRefs = {
|
|
6564
|
+
entryPaths: show.entryPaths,
|
|
6565
|
+
listNames: show.listNames,
|
|
6566
|
+
variableNames: show.variableNames,
|
|
6567
|
+
fileIds: show.fileIds
|
|
6568
|
+
};
|
|
6569
|
+
const hasOtherRefs = Object.values(otherRefs).some(
|
|
6570
|
+
(value) => Array.isArray(value) && value.length > 0
|
|
6571
|
+
);
|
|
6572
|
+
const title = artifactIds.length > 0 ? "[Agent displayed session artifacts]" : "[Agent suggested actions]";
|
|
6573
|
+
return [
|
|
6574
|
+
title,
|
|
6575
|
+
...lines,
|
|
6576
|
+
hasOtherRefs ? `Other shown refs: ${stringifyTranscriptValue(otherRefs, "")}` : null
|
|
6577
|
+
].filter(Boolean).join("\n");
|
|
6403
6578
|
}
|
|
6404
|
-
function normalizeConversationMessage(raw) {
|
|
6579
|
+
function normalizeConversationMessage(raw, artifactsById) {
|
|
6405
6580
|
const record = asRecord3(raw);
|
|
6406
6581
|
if (!record) return null;
|
|
6407
6582
|
const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
|
|
@@ -6413,6 +6588,12 @@ function normalizeConversationMessage(raw) {
|
|
|
6413
6588
|
const id = asString(record.id) || crypto.randomUUID();
|
|
6414
6589
|
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
6415
6590
|
if (!content && !show) return null;
|
|
6591
|
+
const artifactHistory = buildArtifactHistory(show, artifactsById);
|
|
6592
|
+
const historyContent = role === "assistant" ? content && artifactHistory ? `[Assistant reply]
|
|
6593
|
+
${content}
|
|
6594
|
+
|
|
6595
|
+
${artifactHistory}` : content ? `[Assistant reply]
|
|
6596
|
+
${content}` : artifactHistory : void 0;
|
|
6416
6597
|
return {
|
|
6417
6598
|
id,
|
|
6418
6599
|
role,
|
|
@@ -6421,8 +6602,7 @@ function normalizeConversationMessage(raw) {
|
|
|
6421
6602
|
jobId: asString(record.jobId),
|
|
6422
6603
|
promptId: asString(record.promptId),
|
|
6423
6604
|
show,
|
|
6424
|
-
historyContent
|
|
6425
|
-
${content}` : buildArtifactHistory(show) : void 0,
|
|
6605
|
+
historyContent,
|
|
6426
6606
|
source: "conversation"
|
|
6427
6607
|
};
|
|
6428
6608
|
}
|
|
@@ -6465,7 +6645,7 @@ ${assistantContent}`,
|
|
|
6465
6645
|
return entries;
|
|
6466
6646
|
});
|
|
6467
6647
|
}
|
|
6468
|
-
function normalizeAgentMessageEntries(jobId, rawMessages) {
|
|
6648
|
+
function normalizeAgentMessageEntries(jobId, rawMessages, artifactsById) {
|
|
6469
6649
|
return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
6470
6650
|
(left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
|
|
6471
6651
|
).flatMap((message) => {
|
|
@@ -6496,14 +6676,14 @@ ${reply}`,
|
|
|
6496
6676
|
timestamp,
|
|
6497
6677
|
jobId,
|
|
6498
6678
|
show,
|
|
6499
|
-
historyContent: buildArtifactHistory(show),
|
|
6679
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6500
6680
|
source: "job_agent_message"
|
|
6501
6681
|
});
|
|
6502
6682
|
}
|
|
6503
6683
|
return entries;
|
|
6504
6684
|
});
|
|
6505
6685
|
}
|
|
6506
|
-
function buildJobFallbackEntries(jobId, job, sessionHeap) {
|
|
6686
|
+
function buildJobFallbackEntries(jobId, job, sessionHeap, artifactsById) {
|
|
6507
6687
|
const timestamp = asNumber(job.finishedAt) || asNumber(job.startedAt) || asNumber(job.submittedAt) || 0;
|
|
6508
6688
|
const resultPreview = stringifyTranscriptValue(
|
|
6509
6689
|
job.result,
|
|
@@ -6541,7 +6721,7 @@ ${responseText}`,
|
|
|
6541
6721
|
timestamp,
|
|
6542
6722
|
jobId,
|
|
6543
6723
|
show,
|
|
6544
|
-
historyContent: buildArtifactHistory(show),
|
|
6724
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6545
6725
|
source: "job_result"
|
|
6546
6726
|
});
|
|
6547
6727
|
}
|
|
@@ -6595,10 +6775,11 @@ function buildJobCodeEntry(jobId, job) {
|
|
|
6595
6775
|
function buildSessionTranscript(input) {
|
|
6596
6776
|
const liveDoc = input.liveDoc || null;
|
|
6597
6777
|
const sessionHeap = input.sessionHeap || EMPTY_HEAP;
|
|
6778
|
+
const artifactsById = artifactRecordsById(liveDoc);
|
|
6598
6779
|
const transcript = [];
|
|
6599
6780
|
const conversationMessages = asArray(
|
|
6600
6781
|
asRecord3(liveDoc?.conversation)?.messages
|
|
6601
|
-
).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
|
|
6782
|
+
).map((message) => normalizeConversationMessage(message, artifactsById)).filter((message) => Boolean(message));
|
|
6602
6783
|
const conversationPromptIds = new Set(
|
|
6603
6784
|
conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
|
|
6604
6785
|
);
|
|
@@ -6625,7 +6806,8 @@ function buildSessionTranscript(input) {
|
|
|
6625
6806
|
if (!assistantConversationJobIds.has(jobId)) {
|
|
6626
6807
|
const agentEntries = normalizeAgentMessageEntries(
|
|
6627
6808
|
jobId,
|
|
6628
|
-
job.agentMessages
|
|
6809
|
+
job.agentMessages,
|
|
6810
|
+
artifactsById
|
|
6629
6811
|
);
|
|
6630
6812
|
if (agentEntries.length > 0) {
|
|
6631
6813
|
transcript.push(...agentEntries);
|
|
@@ -6634,7 +6816,8 @@ function buildSessionTranscript(input) {
|
|
|
6634
6816
|
...buildJobFallbackEntries(
|
|
6635
6817
|
jobId,
|
|
6636
6818
|
job,
|
|
6637
|
-
sessionHeap
|
|
6819
|
+
sessionHeap,
|
|
6820
|
+
artifactsById
|
|
6638
6821
|
)
|
|
6639
6822
|
);
|
|
6640
6823
|
}
|
|
@@ -10800,16 +10983,107 @@ var StateMachineStateSchema = external_exports.union([
|
|
|
10800
10983
|
external_exports.string(),
|
|
10801
10984
|
external_exports.object({
|
|
10802
10985
|
name: external_exports.string().min(1),
|
|
10986
|
+
label: external_exports.string().optional(),
|
|
10987
|
+
description: external_exports.string().optional(),
|
|
10803
10988
|
isFinal: external_exports.boolean().optional()
|
|
10804
10989
|
}).strict()
|
|
10805
10990
|
]);
|
|
10991
|
+
var StateTransitionInputBindingSchema = external_exports.lazy(
|
|
10992
|
+
() => external_exports.union([
|
|
10993
|
+
external_exports.null(),
|
|
10994
|
+
external_exports.string(),
|
|
10995
|
+
external_exports.number(),
|
|
10996
|
+
external_exports.boolean(),
|
|
10997
|
+
external_exports.array(StateTransitionInputBindingSchema),
|
|
10998
|
+
external_exports.object({
|
|
10999
|
+
const: external_exports.unknown()
|
|
11000
|
+
}).strict(),
|
|
11001
|
+
external_exports.object({
|
|
11002
|
+
from: external_exports.literal("object"),
|
|
11003
|
+
path: external_exports.string().min(1),
|
|
11004
|
+
editable: external_exports.boolean().optional()
|
|
11005
|
+
}).strict(),
|
|
11006
|
+
external_exports.object({
|
|
11007
|
+
from: external_exports.literal("field"),
|
|
11008
|
+
name: external_exports.string().min(1),
|
|
11009
|
+
editable: external_exports.boolean().optional()
|
|
11010
|
+
}).strict(),
|
|
11011
|
+
external_exports.object({
|
|
11012
|
+
from: external_exports.literal("relationship"),
|
|
11013
|
+
name: external_exports.string().min(1),
|
|
11014
|
+
path: external_exports.string().min(1).optional(),
|
|
11015
|
+
many: external_exports.boolean().optional(),
|
|
11016
|
+
editable: external_exports.boolean().optional()
|
|
11017
|
+
}).strict(),
|
|
11018
|
+
external_exports.object({
|
|
11019
|
+
from: external_exports.literal("session"),
|
|
11020
|
+
path: external_exports.string().min(1),
|
|
11021
|
+
editable: external_exports.boolean().optional()
|
|
11022
|
+
}).strict(),
|
|
11023
|
+
external_exports.object({
|
|
11024
|
+
from: external_exports.literal("actor"),
|
|
11025
|
+
path: external_exports.string().min(1),
|
|
11026
|
+
editable: external_exports.boolean().optional()
|
|
11027
|
+
}).strict(),
|
|
11028
|
+
external_exports.record(external_exports.string(), StateTransitionInputBindingSchema)
|
|
11029
|
+
])
|
|
11030
|
+
);
|
|
11031
|
+
var StateTransitionActionSchema = external_exports.object({
|
|
11032
|
+
effect: external_exports.string().min(1),
|
|
11033
|
+
input: external_exports.record(external_exports.string(), StateTransitionInputBindingSchema).optional()
|
|
11034
|
+
}).strict();
|
|
11035
|
+
var StateTransitionAssigneeSchema = external_exports.object({
|
|
11036
|
+
kind: external_exports.string().min(1),
|
|
11037
|
+
from: StateTransitionInputBindingSchema.optional(),
|
|
11038
|
+
role: external_exports.string().optional(),
|
|
11039
|
+
label: external_exports.string().optional()
|
|
11040
|
+
}).strict();
|
|
11041
|
+
var StateTransitionRelatedStateRequirementSchema = external_exports.object({
|
|
11042
|
+
relationship: external_exports.string().min(1),
|
|
11043
|
+
machine: external_exports.string().min(1),
|
|
11044
|
+
state: external_exports.string().min(1),
|
|
11045
|
+
className: external_exports.string().min(1).optional(),
|
|
11046
|
+
label: external_exports.string().optional(),
|
|
11047
|
+
mode: external_exports.enum(["every", "some", "any"]).optional()
|
|
11048
|
+
}).strict();
|
|
11049
|
+
var StateTransitionRequirementsSchema = external_exports.object({
|
|
11050
|
+
fields: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11051
|
+
relationships: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11052
|
+
relatedStates: external_exports.array(StateTransitionRelatedStateRequirementSchema).optional()
|
|
11053
|
+
}).strict();
|
|
11054
|
+
var StateTransitionPermissionSchema = external_exports.union([
|
|
11055
|
+
external_exports.string().min(1),
|
|
11056
|
+
external_exports.object({
|
|
11057
|
+
profile: external_exports.string().min(1).optional(),
|
|
11058
|
+
profileId: external_exports.string().min(1).optional(),
|
|
11059
|
+
label: external_exports.string().optional(),
|
|
11060
|
+
reason: external_exports.string().optional()
|
|
11061
|
+
}).strict()
|
|
11062
|
+
]);
|
|
11063
|
+
var StateTransitionExpectedOutcomeSchema = external_exports.union([
|
|
11064
|
+
external_exports.string().min(1),
|
|
11065
|
+
external_exports.object({
|
|
11066
|
+
machine: external_exports.string().min(1).optional(),
|
|
11067
|
+
state: external_exports.string().min(1),
|
|
11068
|
+
summary: external_exports.string().optional()
|
|
11069
|
+
}).strict()
|
|
11070
|
+
]);
|
|
10806
11071
|
var StateMachineTransitionSchema = external_exports.object({
|
|
10807
11072
|
name: external_exports.string().min(1),
|
|
10808
11073
|
from: external_exports.string().min(1),
|
|
10809
|
-
to: external_exports.string().min(1)
|
|
11074
|
+
to: external_exports.string().min(1),
|
|
11075
|
+
label: external_exports.string().optional(),
|
|
11076
|
+
description: external_exports.string().optional(),
|
|
11077
|
+
action: StateTransitionActionSchema.optional(),
|
|
11078
|
+
assignee: StateTransitionAssigneeSchema.optional(),
|
|
11079
|
+
requirements: StateTransitionRequirementsSchema.optional(),
|
|
11080
|
+
permission: StateTransitionPermissionSchema.optional(),
|
|
11081
|
+
risk: external_exports.enum(["low", "medium", "high"]).optional(),
|
|
11082
|
+
expectedOutcome: StateTransitionExpectedOutcomeSchema.optional()
|
|
10810
11083
|
}).strict();
|
|
10811
11084
|
external_exports.object({
|
|
10812
11085
|
name: external_exports.string().min(1),
|
|
11086
|
+
stateField: external_exports.string().min(1).optional(),
|
|
10813
11087
|
entryState: external_exports.string().min(1),
|
|
10814
11088
|
states: external_exports.array(StateMachineStateSchema).min(1),
|
|
10815
11089
|
transitions: external_exports.array(StateMachineTransitionSchema),
|
|
@@ -10876,6 +11150,16 @@ var PoliciesSchema = external_exports.object({
|
|
|
10876
11150
|
confirmWhen: external_exports.array(PolicyRuleSchema).optional(),
|
|
10877
11151
|
denyWhen: external_exports.array(PolicyRuleSchema).optional()
|
|
10878
11152
|
}).strict();
|
|
11153
|
+
var CreatesSchema = external_exports.union([
|
|
11154
|
+
external_exports.string().min(1),
|
|
11155
|
+
external_exports.object({
|
|
11156
|
+
className: external_exports.string().min(1),
|
|
11157
|
+
idPath: external_exports.string().min(1).optional(),
|
|
11158
|
+
pathPath: external_exports.string().min(1).optional(),
|
|
11159
|
+
statePath: external_exports.string().min(1).optional(),
|
|
11160
|
+
classStateHandle: external_exports.boolean().optional()
|
|
11161
|
+
}).strict()
|
|
11162
|
+
]);
|
|
10879
11163
|
external_exports.object({
|
|
10880
11164
|
postCondition: external_exports.union([
|
|
10881
11165
|
external_exports.string(),
|
|
@@ -10906,6 +11190,7 @@ external_exports.object({
|
|
|
10906
11190
|
mode: external_exports.string().optional()
|
|
10907
11191
|
}).strict()
|
|
10908
11192
|
]).optional(),
|
|
11193
|
+
creates: CreatesSchema.optional(),
|
|
10909
11194
|
access: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10910
11195
|
effectKind: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10911
11196
|
sideEffect: external_exports.enum(["read", "write", "ui", "readonly", "read_only"]).optional(),
|
|
@@ -11133,9 +11418,10 @@ function mergeMethodSummaryPatch(target, patch) {
|
|
|
11133
11418
|
if (patch.metamodels !== void 0) target.metamodels = patch.metamodels;
|
|
11134
11419
|
if (patch.effectBehaviors !== void 0)
|
|
11135
11420
|
target.effectBehaviors = patch.effectBehaviors;
|
|
11421
|
+
if (patch.creates !== void 0) target.creates = patch.creates;
|
|
11136
11422
|
if (patch.static !== void 0) target.static = patch.static;
|
|
11137
11423
|
}
|
|
11138
|
-
function
|
|
11424
|
+
function toPascalCase2(value) {
|
|
11139
11425
|
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
11140
11426
|
}
|
|
11141
11427
|
function normalizeNotesInput(input) {
|
|
@@ -11193,29 +11479,60 @@ function normalizeEffectBehaviorSummary(metamodels) {
|
|
|
11193
11479
|
}
|
|
11194
11480
|
return Object.keys(result).length > 0 ? result : null;
|
|
11195
11481
|
}
|
|
11196
|
-
function
|
|
11197
|
-
if (!
|
|
11198
|
-
|
|
11482
|
+
function normalizeCreationSummary(metamodels) {
|
|
11483
|
+
if (!isObject(metamodels)) return null;
|
|
11484
|
+
let raw = metamodels.creates;
|
|
11485
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11486
|
+
const trimmed = raw.trim();
|
|
11487
|
+
if (trimmed.startsWith("{") || trimmed.startsWith('"')) {
|
|
11488
|
+
try {
|
|
11489
|
+
raw = JSON.parse(trimmed);
|
|
11490
|
+
} catch {
|
|
11491
|
+
return { className: trimmed };
|
|
11492
|
+
}
|
|
11493
|
+
} else {
|
|
11494
|
+
return { className: trimmed };
|
|
11495
|
+
}
|
|
11496
|
+
}
|
|
11497
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11498
|
+
return { className: raw.trim() };
|
|
11199
11499
|
}
|
|
11500
|
+
if (!isObject(raw)) return null;
|
|
11501
|
+
const className = typeof raw.className === "string" && raw.className.trim() ? raw.className.trim() : "";
|
|
11502
|
+
if (!className) return null;
|
|
11503
|
+
return {
|
|
11504
|
+
className,
|
|
11505
|
+
...typeof raw.idPath === "string" && raw.idPath.trim() ? { idPath: raw.idPath.trim() } : {},
|
|
11506
|
+
...typeof raw.pathPath === "string" && raw.pathPath.trim() ? { pathPath: raw.pathPath.trim() } : {},
|
|
11507
|
+
...typeof raw.statePath === "string" && raw.statePath.trim() ? { statePath: raw.statePath.trim() } : {},
|
|
11508
|
+
...typeof raw.classStateHandle === "boolean" ? { classStateHandle: raw.classStateHandle } : {}
|
|
11509
|
+
};
|
|
11510
|
+
}
|
|
11511
|
+
function buildEffectBehaviorDocs(effectBehaviors, creates) {
|
|
11200
11512
|
const docs = [];
|
|
11201
|
-
if (
|
|
11513
|
+
if (creates) {
|
|
11514
|
+
docs.push(
|
|
11515
|
+
`Creation method: creates ${creates.className}. The agent may use generated class-level new-record action methods for this class.`
|
|
11516
|
+
);
|
|
11517
|
+
}
|
|
11518
|
+
if (effectBehaviors?.approvalRequired?.required) {
|
|
11202
11519
|
docs.push(
|
|
11203
11520
|
effectBehaviors.approvalRequired.reason ? `Approval required: ${effectBehaviors.approvalRequired.reason}.` : "Approval required before execution."
|
|
11204
11521
|
);
|
|
11205
11522
|
}
|
|
11206
|
-
if (effectBehaviors
|
|
11523
|
+
if (effectBehaviors?.postCondition) {
|
|
11207
11524
|
docs.push(`Post-condition: ${effectBehaviors.postCondition.condition}.`);
|
|
11208
11525
|
if (effectBehaviors.postCondition.description) {
|
|
11209
11526
|
docs.push(effectBehaviors.postCondition.description);
|
|
11210
11527
|
}
|
|
11211
11528
|
}
|
|
11212
|
-
if (effectBehaviors
|
|
11529
|
+
if (effectBehaviors?.dryRun?.enabled) {
|
|
11213
11530
|
docs.push("Supports dry run.");
|
|
11214
11531
|
if (effectBehaviors.dryRun.description) {
|
|
11215
11532
|
docs.push(effectBehaviors.dryRun.description);
|
|
11216
11533
|
}
|
|
11217
11534
|
}
|
|
11218
|
-
if (effectBehaviors
|
|
11535
|
+
if (effectBehaviors?.reverse) {
|
|
11219
11536
|
if (effectBehaviors.reverse.handler) {
|
|
11220
11537
|
docs.push(`Reverse handler: ${effectBehaviors.reverse.handler}.`);
|
|
11221
11538
|
} else {
|
|
@@ -11274,13 +11591,21 @@ function buildEffectBehaviorMutations(toolPath, spec) {
|
|
|
11274
11591
|
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { set_approval_required(${args}) { kind } } }`
|
|
11275
11592
|
});
|
|
11276
11593
|
}
|
|
11594
|
+
if (spec.creates !== void 0) {
|
|
11595
|
+
mutations.push({
|
|
11596
|
+
label: `set creates on ${toolPath}`,
|
|
11597
|
+
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "creates", label: "creates") { set_string_value(value: ${JSON.stringify(
|
|
11598
|
+
JSON.stringify(spec.creates)
|
|
11599
|
+
)}) { done } } } }`
|
|
11600
|
+
});
|
|
11601
|
+
}
|
|
11277
11602
|
return mutations;
|
|
11278
11603
|
}
|
|
11279
11604
|
function readMethodEffectBehaviors(rawMethod) {
|
|
11605
|
+
const metamodels = isObject(rawMethod.metamodels) ? rawMethod.metamodels : null;
|
|
11280
11606
|
return {
|
|
11281
|
-
effectBehaviors: normalizeEffectBehaviorSummary(
|
|
11282
|
-
|
|
11283
|
-
)
|
|
11607
|
+
effectBehaviors: normalizeEffectBehaviorSummary(metamodels),
|
|
11608
|
+
creates: normalizeCreationSummary(metamodels)
|
|
11284
11609
|
};
|
|
11285
11610
|
}
|
|
11286
11611
|
var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
@@ -11302,6 +11627,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11302
11627
|
{
|
|
11303
11628
|
key: "approvalRequired",
|
|
11304
11629
|
description: "Boolean or `{ required, reason, mode }`."
|
|
11630
|
+
},
|
|
11631
|
+
{
|
|
11632
|
+
key: "creates",
|
|
11633
|
+
description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, classStateHandle }`.'
|
|
11305
11634
|
}
|
|
11306
11635
|
]
|
|
11307
11636
|
},
|
|
@@ -11421,7 +11750,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11421
11750
|
...methodIR,
|
|
11422
11751
|
docs: [
|
|
11423
11752
|
...methodIR.docs,
|
|
11424
|
-
...buildEffectBehaviorDocs(
|
|
11753
|
+
...buildEffectBehaviorDocs(
|
|
11754
|
+
methodSummary.effectBehaviors,
|
|
11755
|
+
methodSummary.creates
|
|
11756
|
+
)
|
|
11425
11757
|
]
|
|
11426
11758
|
};
|
|
11427
11759
|
}
|
|
@@ -11662,15 +11994,50 @@ function toRecordSearchResult(className, node) {
|
|
|
11662
11994
|
return [];
|
|
11663
11995
|
}
|
|
11664
11996
|
) : [];
|
|
11997
|
+
const graphPathId = extractRecordIdFromGraphPath(path2, className);
|
|
11998
|
+
const realIdField = fields.find(
|
|
11999
|
+
(field) => normalizeGraphPathSegment(field.name) === "real_id" && typeof field.value === "string" && field.value.trim()
|
|
12000
|
+
);
|
|
12001
|
+
const id = typeof realIdField?.value === "string" ? realIdField.value.trim() : graphPathId;
|
|
12002
|
+
const rawLabel = typeof node.label === "string" && node.label.trim() ? node.label : "";
|
|
12003
|
+
if (fields.length === 0 && rawLabel && isPlaceholderRecordLabel(rawLabel, graphPathId, path2)) {
|
|
12004
|
+
return null;
|
|
12005
|
+
}
|
|
12006
|
+
const fallbackLabel = displayLabelFromFields(fields);
|
|
12007
|
+
const label = rawLabel && !isPlaceholderRecordLabel(rawLabel, id, path2) ? rawLabel : fallbackLabel || rawLabel || id;
|
|
11665
12008
|
return {
|
|
11666
12009
|
path: path2,
|
|
11667
12010
|
className,
|
|
11668
|
-
id
|
|
11669
|
-
label
|
|
12011
|
+
id,
|
|
12012
|
+
label,
|
|
11670
12013
|
description: typeof node.description === "string" && node.description.trim() ? node.description : null,
|
|
11671
12014
|
fields
|
|
11672
12015
|
};
|
|
11673
12016
|
}
|
|
12017
|
+
function isPlaceholderRecordLabel(label, id, path2) {
|
|
12018
|
+
const normalizedLabel = normalizeGraphPathSegment(label);
|
|
12019
|
+
return normalizedLabel === normalizeGraphPathSegment(id) || normalizedLabel === normalizeGraphPathSegment(path2);
|
|
12020
|
+
}
|
|
12021
|
+
function displayLabelFromFields(fields) {
|
|
12022
|
+
const preferredFieldNames = [
|
|
12023
|
+
"name",
|
|
12024
|
+
"title",
|
|
12025
|
+
"label",
|
|
12026
|
+
"display_name",
|
|
12027
|
+
"file_name",
|
|
12028
|
+
"number",
|
|
12029
|
+
"code"
|
|
12030
|
+
];
|
|
12031
|
+
for (const preferred of preferredFieldNames) {
|
|
12032
|
+
const match = fields.find(
|
|
12033
|
+
(field) => normalizeGraphPathSegment(field.name) === preferred && typeof field.value === "string" && field.value.trim()
|
|
12034
|
+
);
|
|
12035
|
+
if (typeof match?.value === "string") {
|
|
12036
|
+
return match.value.trim();
|
|
12037
|
+
}
|
|
12038
|
+
}
|
|
12039
|
+
return null;
|
|
12040
|
+
}
|
|
11674
12041
|
function normalizeRecordSearchText(value) {
|
|
11675
12042
|
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
|
|
11676
12043
|
}
|
|
@@ -12570,15 +12937,47 @@ var searchableMetamodelPackage = defineMetamodelPackage({
|
|
|
12570
12937
|
|
|
12571
12938
|
// ../metamodel-state-machine/src/index.ts
|
|
12572
12939
|
function normalizeStateMachines(values) {
|
|
12940
|
+
const parseJsonRecord = (value) => {
|
|
12941
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
12942
|
+
return value;
|
|
12943
|
+
}
|
|
12944
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
12945
|
+
try {
|
|
12946
|
+
const parsed = JSON.parse(value);
|
|
12947
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
12948
|
+
} catch {
|
|
12949
|
+
return null;
|
|
12950
|
+
}
|
|
12951
|
+
};
|
|
12952
|
+
const parseJsonValue = (value) => {
|
|
12953
|
+
if (value === null || typeof value === "undefined") return null;
|
|
12954
|
+
if (typeof value !== "string") return value;
|
|
12955
|
+
if (!value.trim()) return null;
|
|
12956
|
+
try {
|
|
12957
|
+
return JSON.parse(value);
|
|
12958
|
+
} catch {
|
|
12959
|
+
return value;
|
|
12960
|
+
}
|
|
12961
|
+
};
|
|
12573
12962
|
return (values || []).map((machine) => {
|
|
12574
12963
|
const states = (machine?.states || []).map((state) => ({
|
|
12575
12964
|
name: String(state?.name || ""),
|
|
12576
|
-
|
|
12965
|
+
label: typeof state?.label === "string" ? state.label : null,
|
|
12966
|
+
description: typeof state?.description === "string" ? state.description : null,
|
|
12967
|
+
isFinal: Boolean(state?.is_final ?? state?.isFinal)
|
|
12577
12968
|
})).filter((state) => state.name.length > 0);
|
|
12578
12969
|
const transitions = (machine?.transitions || []).map((transition) => ({
|
|
12579
12970
|
name: String(transition?.name || ""),
|
|
12580
12971
|
from: String(transition?.from?.name || ""),
|
|
12581
|
-
to: String(transition?.to?.name || "")
|
|
12972
|
+
to: String(transition?.to?.name || ""),
|
|
12973
|
+
label: typeof transition?.label === "string" ? transition.label : null,
|
|
12974
|
+
description: typeof transition?.description === "string" ? transition.description : null,
|
|
12975
|
+
action: parseJsonRecord(transition?.action) || parseJsonRecord(transition?.action_json),
|
|
12976
|
+
assignee: parseJsonRecord(transition?.assignee) || parseJsonRecord(transition?.assignee_json),
|
|
12977
|
+
requirements: parseJsonRecord(transition?.requirements) || parseJsonRecord(transition?.requirements_json),
|
|
12978
|
+
permission: parseJsonValue(transition?.permission) ?? parseJsonValue(transition?.permission_json),
|
|
12979
|
+
risk: transition?.risk === "low" || transition?.risk === "medium" || transition?.risk === "high" ? transition.risk : null,
|
|
12980
|
+
expectedOutcome: parseJsonValue(transition?.expectedOutcome) ?? parseJsonValue(transition?.expected_outcome_json)
|
|
12582
12981
|
})).filter(
|
|
12583
12982
|
(transition) => transition.name.length > 0 && transition.from.length > 0 && transition.to.length > 0
|
|
12584
12983
|
);
|
|
@@ -12592,7 +12991,7 @@ function normalizeStateMachines(values) {
|
|
|
12592
12991
|
}).filter((machine) => machine.name.length > 0);
|
|
12593
12992
|
}
|
|
12594
12993
|
function stateTypeName(className, machineName) {
|
|
12595
|
-
return `${
|
|
12994
|
+
return `${toPascalCase2(className)}${toPascalCase2(machineName)}`;
|
|
12596
12995
|
}
|
|
12597
12996
|
function transitionTypeName(className, machineName) {
|
|
12598
12997
|
return `${stateTypeName(className, machineName)}Transition`;
|
|
@@ -12600,6 +12999,15 @@ function transitionTypeName(className, machineName) {
|
|
|
12600
12999
|
function pathTypeName(className, machineName) {
|
|
12601
13000
|
return `${stateTypeName(className, machineName)}Path`;
|
|
12602
13001
|
}
|
|
13002
|
+
function methodToken(value) {
|
|
13003
|
+
const token = String(value || "").trim().replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
13004
|
+
return token || "state";
|
|
13005
|
+
}
|
|
13006
|
+
function transitionActionsForMachine(machine) {
|
|
13007
|
+
return Object.fromEntries(
|
|
13008
|
+
(machine.transitions || []).filter((transition) => transition.action?.effect).map((transition) => [transition.name, transition.action])
|
|
13009
|
+
);
|
|
13010
|
+
}
|
|
12603
13011
|
function normalizeStateDefinitions(machine) {
|
|
12604
13012
|
const finalStates = new Set(machine.finalStates || []);
|
|
12605
13013
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -12613,6 +13021,8 @@ function normalizeStateDefinitions(machine) {
|
|
|
12613
13021
|
}
|
|
12614
13022
|
states.set(rawState.name, {
|
|
12615
13023
|
name: rawState.name,
|
|
13024
|
+
label: rawState.label,
|
|
13025
|
+
description: rawState.description,
|
|
12616
13026
|
isFinal: Boolean(rawState.isFinal) || finalStates.has(rawState.name)
|
|
12617
13027
|
});
|
|
12618
13028
|
}
|
|
@@ -12624,6 +13034,44 @@ function normalizeStateDefinitions(machine) {
|
|
|
12624
13034
|
}
|
|
12625
13035
|
return [...states.values()];
|
|
12626
13036
|
}
|
|
13037
|
+
function transitionMetadataGraphqlArgs(transition) {
|
|
13038
|
+
const args = [];
|
|
13039
|
+
if (typeof transition.label === "string") {
|
|
13040
|
+
args.push(`label: ${JSON.stringify(transition.label)}`);
|
|
13041
|
+
}
|
|
13042
|
+
if (typeof transition.description === "string") {
|
|
13043
|
+
args.push(`description: ${JSON.stringify(transition.description)}`);
|
|
13044
|
+
}
|
|
13045
|
+
if (transition.action) {
|
|
13046
|
+
args.push(
|
|
13047
|
+
`action_json: ${JSON.stringify(JSON.stringify(transition.action))}`
|
|
13048
|
+
);
|
|
13049
|
+
}
|
|
13050
|
+
if (transition.assignee) {
|
|
13051
|
+
args.push(
|
|
13052
|
+
`assignee_json: ${JSON.stringify(JSON.stringify(transition.assignee))}`
|
|
13053
|
+
);
|
|
13054
|
+
}
|
|
13055
|
+
if (transition.requirements) {
|
|
13056
|
+
args.push(
|
|
13057
|
+
`requirements_json: ${JSON.stringify(JSON.stringify(transition.requirements))}`
|
|
13058
|
+
);
|
|
13059
|
+
}
|
|
13060
|
+
if (transition.permission) {
|
|
13061
|
+
args.push(
|
|
13062
|
+
`permission_json: ${JSON.stringify(JSON.stringify(transition.permission))}`
|
|
13063
|
+
);
|
|
13064
|
+
}
|
|
13065
|
+
if (transition.risk) {
|
|
13066
|
+
args.push(`risk: ${JSON.stringify(transition.risk)}`);
|
|
13067
|
+
}
|
|
13068
|
+
if (transition.expectedOutcome) {
|
|
13069
|
+
args.push(
|
|
13070
|
+
`expected_outcome_json: ${JSON.stringify(JSON.stringify(transition.expectedOutcome))}`
|
|
13071
|
+
);
|
|
13072
|
+
}
|
|
13073
|
+
return args.length > 0 ? `, ${args.join(", ")}` : "";
|
|
13074
|
+
}
|
|
12627
13075
|
function buildStateMachineModelMutations(modelPath, machines) {
|
|
12628
13076
|
const mutations = [];
|
|
12629
13077
|
for (const machine of machines || []) {
|
|
@@ -12634,12 +13082,13 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12634
13082
|
)}, entry_state: ${JSON.stringify(machine.entryState)}) { name } } }`
|
|
12635
13083
|
});
|
|
12636
13084
|
for (const state of normalizeStateDefinitions(machine)) {
|
|
12637
|
-
if (state.name === machine.entryState && !state.isFinal)
|
|
13085
|
+
if (state.name === machine.entryState && !state.isFinal && !state.label && !state.description)
|
|
13086
|
+
continue;
|
|
12638
13087
|
mutations.push({
|
|
12639
13088
|
label: `add state ${state.name} on ${modelPath}.${machine.name}`,
|
|
12640
13089
|
query: `mutation { at(path: ${JSON.stringify(modelPath)}) { state_machine(name: ${JSON.stringify(
|
|
12641
13090
|
machine.name
|
|
12642
|
-
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}) { name } } } }`
|
|
13091
|
+
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}, label: ${JSON.stringify(state.label || null)}, description: ${JSON.stringify(state.description || null)}) { name } } } }`
|
|
12643
13092
|
});
|
|
12644
13093
|
}
|
|
12645
13094
|
for (const transition of machine.transitions || []) {
|
|
@@ -12651,7 +13100,7 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12651
13100
|
transition.name
|
|
12652
13101
|
)}, from: ${JSON.stringify(transition.from)}, to: ${JSON.stringify(
|
|
12653
13102
|
transition.to
|
|
12654
|
-
)}) { name } } } }`
|
|
13103
|
+
)}${transitionMetadataGraphqlArgs(transition)}) { name } } } }`
|
|
12655
13104
|
});
|
|
12656
13105
|
}
|
|
12657
13106
|
}
|
|
@@ -12678,7 +13127,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12678
13127
|
const transitionName = transitionTypeName(classSummary.name, machine.name);
|
|
12679
13128
|
pathTypeName(classSummary.name, machine.name);
|
|
12680
13129
|
const docsPrefix = `${classSummary.name}.${machine.name}`;
|
|
12681
|
-
|
|
13130
|
+
const methods = [
|
|
12682
13131
|
{
|
|
12683
13132
|
name: `get_${machine.name}`,
|
|
12684
13133
|
docs: [`Get the current ${docsPrefix} state.`],
|
|
@@ -12701,7 +13150,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12701
13150
|
],
|
|
12702
13151
|
static: false,
|
|
12703
13152
|
params: [{ name: "target", type: stateName }],
|
|
12704
|
-
returnType: `Promise<${
|
|
13153
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
12705
13154
|
runtime: {
|
|
12706
13155
|
kind: "state_machine",
|
|
12707
13156
|
machineName: machine.name,
|
|
@@ -12774,6 +13223,99 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12774
13223
|
}
|
|
12775
13224
|
}
|
|
12776
13225
|
];
|
|
13226
|
+
const creationMethods = (classSummary.methods || []).filter(
|
|
13227
|
+
(method) => method.static === true && Boolean(method.creates) && method.creates?.className === classSummary.name && typeof method.effectKey === "string" && method.effectKey.length > 0
|
|
13228
|
+
);
|
|
13229
|
+
for (const state of machine.states) {
|
|
13230
|
+
const stateNameValue = typeof state === "string" ? state : String(state?.name || "");
|
|
13231
|
+
if (!stateNameValue) continue;
|
|
13232
|
+
const token = methodToken(stateNameValue);
|
|
13233
|
+
methods.push(
|
|
13234
|
+
{
|
|
13235
|
+
name: `reach_${machine.name}_to_${token}`,
|
|
13236
|
+
docs: [`Reach ${docsPrefix} state ${stateNameValue}.`],
|
|
13237
|
+
static: false,
|
|
13238
|
+
params: [],
|
|
13239
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
13240
|
+
runtime: {
|
|
13241
|
+
kind: "state_machine",
|
|
13242
|
+
machineName: machine.name,
|
|
13243
|
+
className: classSummary.name,
|
|
13244
|
+
stateTypeName: stateName,
|
|
13245
|
+
transitionTypeName: transitionName,
|
|
13246
|
+
operation: "reach",
|
|
13247
|
+
targetState: stateNameValue,
|
|
13248
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13249
|
+
}
|
|
13250
|
+
},
|
|
13251
|
+
{
|
|
13252
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13253
|
+
docs: [
|
|
13254
|
+
`Prepare a reviewable artifact that can move ${docsPrefix} to ${stateNameValue}.`
|
|
13255
|
+
],
|
|
13256
|
+
static: false,
|
|
13257
|
+
params: [],
|
|
13258
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13259
|
+
runtime: {
|
|
13260
|
+
kind: "state_machine",
|
|
13261
|
+
machineName: machine.name,
|
|
13262
|
+
className: classSummary.name,
|
|
13263
|
+
stateTypeName: stateName,
|
|
13264
|
+
transitionTypeName: transitionName,
|
|
13265
|
+
operation: "prepare_reach",
|
|
13266
|
+
targetState: stateNameValue,
|
|
13267
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13268
|
+
}
|
|
13269
|
+
}
|
|
13270
|
+
);
|
|
13271
|
+
for (const creationMethod of creationMethods) {
|
|
13272
|
+
const creationRuntime = {
|
|
13273
|
+
kind: "state_machine",
|
|
13274
|
+
machineName: machine.name,
|
|
13275
|
+
className: classSummary.name,
|
|
13276
|
+
stateTypeName: stateName,
|
|
13277
|
+
transitionTypeName: transitionName,
|
|
13278
|
+
operation: "prepare_create_reach",
|
|
13279
|
+
targetState: stateNameValue,
|
|
13280
|
+
transitionActions: transitionActionsForMachine(machine),
|
|
13281
|
+
creation: {
|
|
13282
|
+
methodName: creationMethod.name,
|
|
13283
|
+
effectKey: creationMethod.effectKey || creationMethod.name,
|
|
13284
|
+
inputSchema: creationMethod.inputSchema,
|
|
13285
|
+
outputSchema: creationMethod.outputSchema,
|
|
13286
|
+
creates: creationMethod.creates
|
|
13287
|
+
}
|
|
13288
|
+
};
|
|
13289
|
+
const viaName = `prepare_${machine.name}_to_${token}_via_${methodToken(creationMethod.name)}`;
|
|
13290
|
+
methods.push({
|
|
13291
|
+
name: viaName,
|
|
13292
|
+
docs: [
|
|
13293
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name} through ${creationMethod.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13294
|
+
],
|
|
13295
|
+
static: true,
|
|
13296
|
+
params: [
|
|
13297
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13298
|
+
],
|
|
13299
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13300
|
+
runtime: creationRuntime
|
|
13301
|
+
});
|
|
13302
|
+
if (creationMethods.length === 1) {
|
|
13303
|
+
methods.push({
|
|
13304
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13305
|
+
docs: [
|
|
13306
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13307
|
+
],
|
|
13308
|
+
static: true,
|
|
13309
|
+
params: [
|
|
13310
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13311
|
+
],
|
|
13312
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13313
|
+
runtime: creationRuntime
|
|
13314
|
+
});
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
13317
|
+
}
|
|
13318
|
+
return methods;
|
|
12777
13319
|
}
|
|
12778
13320
|
function readStateMachineSummaries(rawClass) {
|
|
12779
13321
|
return {
|
|
@@ -12796,8 +13338,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12796
13338
|
type StateMachineMutation {
|
|
12797
13339
|
name: String!
|
|
12798
13340
|
state_machine: StateMachine!
|
|
12799
|
-
add_state(name: String!, is_final: Boolean): StateMachineMutation!
|
|
12800
|
-
add_transition(name: String!, from: String!, to: String
|
|
13341
|
+
add_state(name: String!, is_final: Boolean, label: String, description: String): StateMachineMutation!
|
|
13342
|
+
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): StateMachineMutation!
|
|
12801
13343
|
activate_transition(name: String!): StateMachineMutation!
|
|
12802
13344
|
}
|
|
12803
13345
|
|
|
@@ -12814,6 +13356,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12814
13356
|
type StateMachineSnapshotMutation {
|
|
12815
13357
|
snapshot: StateMachineSnapshot!
|
|
12816
13358
|
activate_transition(name: String!): StateMachineSnapshotMutation!
|
|
13359
|
+
observe_state(state: String!, force: Boolean, source: String): StateMachineSnapshotMutation!
|
|
12817
13360
|
}
|
|
12818
13361
|
|
|
12819
13362
|
type StateMachine {
|
|
@@ -12833,6 +13376,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12833
13376
|
|
|
12834
13377
|
type StateMachineState {
|
|
12835
13378
|
name: String!
|
|
13379
|
+
label: String
|
|
13380
|
+
description: String
|
|
12836
13381
|
is_final: Boolean!
|
|
12837
13382
|
}
|
|
12838
13383
|
|
|
@@ -12840,6 +13385,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12840
13385
|
name: String!
|
|
12841
13386
|
from: StateMachineState!
|
|
12842
13387
|
to: StateMachineState!
|
|
13388
|
+
label: String
|
|
13389
|
+
description: String
|
|
13390
|
+
action_json: String
|
|
13391
|
+
assignee_json: String
|
|
13392
|
+
requirements_json: String
|
|
13393
|
+
permission_json: String
|
|
13394
|
+
risk: String
|
|
13395
|
+
expected_outcome_json: String
|
|
12843
13396
|
}
|
|
12844
13397
|
|
|
12845
13398
|
type StateMachinePath {
|
|
@@ -12892,23 +13445,47 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12892
13445
|
StateMachineMutation: {
|
|
12893
13446
|
name: (value) => value.name,
|
|
12894
13447
|
state_machine: async (value) => await run(value.target.state_machine(value.name)),
|
|
12895
|
-
add_state: async (value, { name, is_final }) => {
|
|
13448
|
+
add_state: async (value, { name, is_final, label, description }) => {
|
|
12896
13449
|
await run(
|
|
12897
13450
|
value.target.add_state_machine_state(
|
|
12898
13451
|
value.name,
|
|
12899
13452
|
name,
|
|
12900
|
-
is_final ?? false
|
|
13453
|
+
is_final ?? false,
|
|
13454
|
+
label,
|
|
13455
|
+
description
|
|
12901
13456
|
)
|
|
12902
13457
|
);
|
|
12903
13458
|
return value;
|
|
12904
13459
|
},
|
|
12905
|
-
add_transition: async (value, {
|
|
13460
|
+
add_transition: async (value, {
|
|
13461
|
+
name,
|
|
13462
|
+
from,
|
|
13463
|
+
to,
|
|
13464
|
+
label,
|
|
13465
|
+
description,
|
|
13466
|
+
action_json,
|
|
13467
|
+
assignee_json,
|
|
13468
|
+
requirements_json,
|
|
13469
|
+
permission_json,
|
|
13470
|
+
risk,
|
|
13471
|
+
expected_outcome_json
|
|
13472
|
+
}) => {
|
|
12906
13473
|
await run(
|
|
12907
13474
|
value.target.add_state_machine_transition(
|
|
12908
13475
|
value.name,
|
|
12909
13476
|
name,
|
|
12910
13477
|
from,
|
|
12911
|
-
to
|
|
13478
|
+
to,
|
|
13479
|
+
{
|
|
13480
|
+
label,
|
|
13481
|
+
description,
|
|
13482
|
+
actionJson: action_json,
|
|
13483
|
+
assigneeJson: assignee_json,
|
|
13484
|
+
requirementsJson: requirements_json,
|
|
13485
|
+
permissionJson: permission_json,
|
|
13486
|
+
risk,
|
|
13487
|
+
expectedOutcomeJson: expected_outcome_json
|
|
13488
|
+
}
|
|
12912
13489
|
)
|
|
12913
13490
|
);
|
|
12914
13491
|
return value;
|
|
@@ -12927,16 +13504,37 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12927
13504
|
value.target.activate_state_machine_transition(value.name, name)
|
|
12928
13505
|
);
|
|
12929
13506
|
return value;
|
|
13507
|
+
},
|
|
13508
|
+
observe_state: async (value, { state, force, source }) => {
|
|
13509
|
+
await run(
|
|
13510
|
+
value.target.observe_state_machine_state(
|
|
13511
|
+
value.name,
|
|
13512
|
+
state,
|
|
13513
|
+
force === true,
|
|
13514
|
+
source
|
|
13515
|
+
)
|
|
13516
|
+
);
|
|
13517
|
+
return value;
|
|
12930
13518
|
}
|
|
12931
13519
|
},
|
|
12932
13520
|
StateMachineState: {
|
|
12933
13521
|
name: (value) => value.name,
|
|
13522
|
+
label: (value) => value.label || null,
|
|
13523
|
+
description: (value) => value.description || null,
|
|
12934
13524
|
is_final: (value) => value.is_final
|
|
12935
13525
|
},
|
|
12936
13526
|
StateMachineTransition: {
|
|
12937
13527
|
name: (value) => value.name,
|
|
12938
13528
|
from: (value) => value.from_state || { name: value.from, is_final: false },
|
|
12939
|
-
to: (value) => value.to_state || { name: value.to, is_final: false }
|
|
13529
|
+
to: (value) => value.to_state || { name: value.to, is_final: false },
|
|
13530
|
+
label: (value) => value.label || null,
|
|
13531
|
+
description: (value) => value.description || null,
|
|
13532
|
+
action_json: (value) => value.action_json || null,
|
|
13533
|
+
assignee_json: (value) => value.assignee_json || null,
|
|
13534
|
+
requirements_json: (value) => value.requirements_json || null,
|
|
13535
|
+
permission_json: (value) => value.permission_json || null,
|
|
13536
|
+
risk: (value) => value.risk || null,
|
|
13537
|
+
expected_outcome_json: (value) => value.expected_outcome_json || null
|
|
12940
13538
|
},
|
|
12941
13539
|
StateMachinePath: {
|
|
12942
13540
|
states: (value) => value.states,
|
|
@@ -13003,6 +13601,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
13003
13601
|
name
|
|
13004
13602
|
from { name }
|
|
13005
13603
|
to { name }
|
|
13604
|
+
label
|
|
13605
|
+
description
|
|
13606
|
+
action_json
|
|
13607
|
+
assignee_json
|
|
13608
|
+
requirements_json
|
|
13609
|
+
permission_json
|
|
13610
|
+
risk
|
|
13611
|
+
expected_outcome_json
|
|
13006
13612
|
}
|
|
13007
13613
|
}`
|
|
13008
13614
|
]
|
|
@@ -13256,6 +13862,26 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
13256
13862
|
var BUILTIN_MODULES = {
|
|
13257
13863
|
standard_modules: STANDARD_MODULES_OPERATIONS
|
|
13258
13864
|
};
|
|
13865
|
+
function stateNameFromMethodName(methodName) {
|
|
13866
|
+
const raw = methodName.startsWith("to") ? methodName.slice(2) : methodName;
|
|
13867
|
+
return raw.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
13868
|
+
}
|
|
13869
|
+
function appendQueryOptions(searchParams, query) {
|
|
13870
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
13871
|
+
if (value === null || typeof value === "undefined" || value === "") {
|
|
13872
|
+
continue;
|
|
13873
|
+
}
|
|
13874
|
+
if (value instanceof Date) {
|
|
13875
|
+
searchParams.set(key, value.toISOString());
|
|
13876
|
+
continue;
|
|
13877
|
+
}
|
|
13878
|
+
if (Array.isArray(value)) {
|
|
13879
|
+
if (value.length > 0) searchParams.set(key, value.join(","));
|
|
13880
|
+
continue;
|
|
13881
|
+
}
|
|
13882
|
+
searchParams.set(key, String(value));
|
|
13883
|
+
}
|
|
13884
|
+
}
|
|
13259
13885
|
var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
|
|
13260
13886
|
var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
|
|
13261
13887
|
var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
|
|
@@ -13286,8 +13912,20 @@ function bodyInitFromSessionFileUpload(body) {
|
|
|
13286
13912
|
return body;
|
|
13287
13913
|
}
|
|
13288
13914
|
var EFFECT_CATALOG_SYNC_TIMEOUT_MS = 12e4;
|
|
13915
|
+
var EFFECT_CATALOG_SYNC_BATCH_SIZE = 20;
|
|
13289
13916
|
var EFFECT_CATALOG_SYNC_RETRY_COUNT = 3;
|
|
13290
13917
|
var EFFECT_CATALOG_SYNC_RETRY_DELAY_MS = 1e3;
|
|
13918
|
+
function chunkItems(items, batchSize) {
|
|
13919
|
+
const chunks = [];
|
|
13920
|
+
for (let offset = 0; offset < items.length; offset += batchSize) {
|
|
13921
|
+
chunks.push(items.slice(offset, offset + batchSize));
|
|
13922
|
+
}
|
|
13923
|
+
return chunks;
|
|
13924
|
+
}
|
|
13925
|
+
function isUnsupportedEffectCatalogMutation(error) {
|
|
13926
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13927
|
+
return message.includes("Unknown RPC method: effects.resetCatalog") || message.includes("Unknown RPC method: effects.addCatalog") || message.includes("Method not found: effects.resetCatalog") || message.includes("Method not found: effects.addCatalog");
|
|
13928
|
+
}
|
|
13291
13929
|
function planRecordObjectsChunks(records, batchSize) {
|
|
13292
13930
|
const total = records.length;
|
|
13293
13931
|
const size = Math.max(1, Math.min(batchSize, total));
|
|
@@ -13299,6 +13937,23 @@ function planRecordObjectsChunks(records, batchSize) {
|
|
|
13299
13937
|
}
|
|
13300
13938
|
return plans;
|
|
13301
13939
|
}
|
|
13940
|
+
function preserveRecordObjectRealId(record) {
|
|
13941
|
+
const realId = record.id.trim();
|
|
13942
|
+
if (!realId) {
|
|
13943
|
+
return record;
|
|
13944
|
+
}
|
|
13945
|
+
const fields = record.fields || {};
|
|
13946
|
+
if (typeof fields.real_id === "string" && fields.real_id.trim()) {
|
|
13947
|
+
return record;
|
|
13948
|
+
}
|
|
13949
|
+
return {
|
|
13950
|
+
...record,
|
|
13951
|
+
fields: {
|
|
13952
|
+
...fields,
|
|
13953
|
+
real_id: realId
|
|
13954
|
+
}
|
|
13955
|
+
};
|
|
13956
|
+
}
|
|
13302
13957
|
function computeEffectKey2(effect) {
|
|
13303
13958
|
const attachedClass = effect.className?.trim();
|
|
13304
13959
|
if (!attachedClass) {
|
|
@@ -13536,11 +14191,105 @@ var Environment = class _Environment {
|
|
|
13536
14191
|
getAwaitingCount: async () => this.getAwaitingRecordCount()
|
|
13537
14192
|
};
|
|
13538
14193
|
}
|
|
14194
|
+
/**
|
|
14195
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14196
|
+
* own the customer application's state machine.
|
|
14197
|
+
*/
|
|
14198
|
+
async recordState(input) {
|
|
14199
|
+
const { machine, state, ...target } = input;
|
|
14200
|
+
if (!machine.trim()) {
|
|
14201
|
+
throw new Error("State update requires a machine name");
|
|
14202
|
+
}
|
|
14203
|
+
if (!state.trim()) {
|
|
14204
|
+
throw new Error("State update requires a state");
|
|
14205
|
+
}
|
|
14206
|
+
return this.recordObject({
|
|
14207
|
+
className: target.className,
|
|
14208
|
+
id: target.id,
|
|
14209
|
+
...target.label ? { label: target.label } : {},
|
|
14210
|
+
...target.fields ? { fields: target.fields } : {},
|
|
14211
|
+
...target.relationships ? { relationships: target.relationships } : {},
|
|
14212
|
+
states: {
|
|
14213
|
+
[machine.trim()]: {
|
|
14214
|
+
state: state.trim(),
|
|
14215
|
+
...target.source ? { source: target.source } : {},
|
|
14216
|
+
...target.cause ? { cause: target.cause } : {},
|
|
14217
|
+
...target.actorId ? { actorId: target.actorId } : {},
|
|
14218
|
+
...target.observedAt !== void 0 ? { observedAt: target.observedAt } : {},
|
|
14219
|
+
...target.force !== void 0 ? { force: target.force } : {},
|
|
14220
|
+
...target.metadata ? { metadata: target.metadata } : {}
|
|
14221
|
+
}
|
|
14222
|
+
}
|
|
14223
|
+
});
|
|
14224
|
+
}
|
|
14225
|
+
/**
|
|
14226
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14227
|
+
* own the customer application's state machine.
|
|
14228
|
+
*
|
|
14229
|
+
* Example:
|
|
14230
|
+
* `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
|
|
14231
|
+
*/
|
|
14232
|
+
state(target) {
|
|
14233
|
+
const observe = async (machineName, stateName, input = {}) => {
|
|
14234
|
+
const observedState = input.observedState || input.state || stateName;
|
|
14235
|
+
if (!observedState) {
|
|
14236
|
+
throw new Error("State observation requires a target state");
|
|
14237
|
+
}
|
|
14238
|
+
return this.recordState({
|
|
14239
|
+
...target,
|
|
14240
|
+
machine: machineName,
|
|
14241
|
+
state: observedState,
|
|
14242
|
+
...input.source ? { source: input.source } : {},
|
|
14243
|
+
...input.cause ? { cause: input.cause } : {},
|
|
14244
|
+
...input.actorId ? { actorId: input.actorId } : {},
|
|
14245
|
+
...input.observedAt !== void 0 ? { observedAt: input.observedAt } : {},
|
|
14246
|
+
...input.force !== void 0 ? { force: input.force } : {},
|
|
14247
|
+
...input.metadata ? { metadata: input.metadata } : {}
|
|
14248
|
+
});
|
|
14249
|
+
};
|
|
14250
|
+
return new Proxy(
|
|
14251
|
+
{},
|
|
14252
|
+
{
|
|
14253
|
+
get: (_target, machineProperty) => {
|
|
14254
|
+
if (typeof machineProperty !== "string") return void 0;
|
|
14255
|
+
return new Proxy(
|
|
14256
|
+
{},
|
|
14257
|
+
{
|
|
14258
|
+
get: (_machineTarget, stateProperty) => {
|
|
14259
|
+
if (stateProperty === "to") {
|
|
14260
|
+
return (stateName, input) => observe(machineProperty, stateName, input || {});
|
|
14261
|
+
}
|
|
14262
|
+
if (typeof stateProperty !== "string") return void 0;
|
|
14263
|
+
return (input) => observe(
|
|
14264
|
+
machineProperty,
|
|
14265
|
+
stateNameFromMethodName(stateProperty),
|
|
14266
|
+
input || {}
|
|
14267
|
+
);
|
|
14268
|
+
}
|
|
14269
|
+
}
|
|
14270
|
+
);
|
|
14271
|
+
}
|
|
14272
|
+
}
|
|
14273
|
+
);
|
|
14274
|
+
}
|
|
13539
14275
|
get feedback() {
|
|
13540
14276
|
return {
|
|
13541
14277
|
list: async () => this.listFeedback()
|
|
13542
14278
|
};
|
|
13543
14279
|
}
|
|
14280
|
+
get manualActions() {
|
|
14281
|
+
return {
|
|
14282
|
+
record: (input) => this.recordManualAction(input),
|
|
14283
|
+
list: (options = {}) => this.listManualActions(options),
|
|
14284
|
+
suggest: (options = {}) => this.suggestManualActions(options)
|
|
14285
|
+
};
|
|
14286
|
+
}
|
|
14287
|
+
get artifactApprovals() {
|
|
14288
|
+
return {
|
|
14289
|
+
list: (options = {}) => this.listArtifactApprovals(options),
|
|
14290
|
+
decide: (approvalTaskId, input) => this.decideArtifactApproval(approvalTaskId, input)
|
|
14291
|
+
};
|
|
14292
|
+
}
|
|
13544
14293
|
/**
|
|
13545
14294
|
* Sessionless environments do not own a live transport, so disconnecting the
|
|
13546
14295
|
* environment handle itself is a no-op. This keeps the public surface
|
|
@@ -13619,6 +14368,50 @@ var Environment = class _Environment {
|
|
|
13619
14368
|
const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
|
|
13620
14369
|
return Array.isArray(response.items) ? response.items : [];
|
|
13621
14370
|
}
|
|
14371
|
+
async recordManualAction(input) {
|
|
14372
|
+
const body = {
|
|
14373
|
+
...input,
|
|
14374
|
+
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
|
|
14375
|
+
};
|
|
14376
|
+
return this.controlPlaneRequest(
|
|
14377
|
+
`/control/environments/${this.environmentId}/manual-actions`,
|
|
14378
|
+
{
|
|
14379
|
+
method: "POST",
|
|
14380
|
+
body: JSON.stringify(body)
|
|
14381
|
+
}
|
|
14382
|
+
);
|
|
14383
|
+
}
|
|
14384
|
+
async listManualActions(options = {}) {
|
|
14385
|
+
const query = new URLSearchParams();
|
|
14386
|
+
appendQueryOptions(query, options);
|
|
14387
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14388
|
+
return this.controlPlaneRequest(`/control/environments/${this.environmentId}/manual-actions${suffix}`);
|
|
14389
|
+
}
|
|
14390
|
+
async suggestManualActions(options = {}) {
|
|
14391
|
+
const query = new URLSearchParams();
|
|
14392
|
+
appendQueryOptions(query, options);
|
|
14393
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14394
|
+
return this.controlPlaneRequest(
|
|
14395
|
+
`/control/environments/${this.environmentId}/manual-actions/suggestions${suffix}`
|
|
14396
|
+
);
|
|
14397
|
+
}
|
|
14398
|
+
async listArtifactApprovals(options = {}) {
|
|
14399
|
+
const query = new URLSearchParams();
|
|
14400
|
+
appendQueryOptions(query, options);
|
|
14401
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14402
|
+
return this.controlPlaneRequest(
|
|
14403
|
+
`/control/environments/${this.environmentId}/artifact-approvals${suffix}`
|
|
14404
|
+
);
|
|
14405
|
+
}
|
|
14406
|
+
async decideArtifactApproval(approvalTaskId, input) {
|
|
14407
|
+
return this.controlPlaneRequest(
|
|
14408
|
+
`/control/environments/${this.environmentId}/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
14409
|
+
{
|
|
14410
|
+
method: "POST",
|
|
14411
|
+
body: JSON.stringify(input)
|
|
14412
|
+
}
|
|
14413
|
+
);
|
|
14414
|
+
}
|
|
13622
14415
|
getRuntimeBaseUrl() {
|
|
13623
14416
|
return deriveRuntimeBaseUrl(this._apiEndpoint);
|
|
13624
14417
|
}
|
|
@@ -14443,10 +15236,11 @@ var Environment = class _Environment {
|
|
|
14443
15236
|
if (!Array.isArray(records) || records.length === 0) {
|
|
14444
15237
|
return [];
|
|
14445
15238
|
}
|
|
15239
|
+
const recordsToWrite = records.map(preserveRecordObjectRealId);
|
|
14446
15240
|
const batchSize = Math.max(
|
|
14447
15241
|
1,
|
|
14448
15242
|
Math.min(
|
|
14449
|
-
|
|
15243
|
+
recordsToWrite.length,
|
|
14450
15244
|
options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
|
|
14451
15245
|
)
|
|
14452
15246
|
);
|
|
@@ -14454,8 +15248,8 @@ var Environment = class _Environment {
|
|
|
14454
15248
|
MAX_RECORD_OBJECTS_CONCURRENCY,
|
|
14455
15249
|
Math.max(1, options?.concurrency ?? 1)
|
|
14456
15250
|
);
|
|
14457
|
-
const plans = planRecordObjectsChunks(
|
|
14458
|
-
const total =
|
|
15251
|
+
const plans = planRecordObjectsChunks(recordsToWrite, batchSize);
|
|
15252
|
+
const total = recordsToWrite.length;
|
|
14459
15253
|
const results = new Array(total);
|
|
14460
15254
|
const onChunk = options?.onChunkComplete;
|
|
14461
15255
|
for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
|
|
@@ -14526,12 +15320,13 @@ var Environment = class _Environment {
|
|
|
14526
15320
|
* synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
|
|
14527
15321
|
*/
|
|
14528
15322
|
async enqueueRecordImport(records, options = {}) {
|
|
15323
|
+
const recordsToImport = records.map(preserveRecordObjectRealId);
|
|
14529
15324
|
return this.controlPlaneRequest(
|
|
14530
15325
|
`/control/environments/${this.environmentId}/record-imports`,
|
|
14531
15326
|
{
|
|
14532
15327
|
method: "POST",
|
|
14533
15328
|
body: JSON.stringify({
|
|
14534
|
-
records,
|
|
15329
|
+
records: recordsToImport,
|
|
14535
15330
|
batchSize: options.batchSize,
|
|
14536
15331
|
setupRunId: options.setupRunId,
|
|
14537
15332
|
writeMode: options.writeMode
|
|
@@ -14639,11 +15434,7 @@ var EnvironmentSession = class extends Session {
|
|
|
14639
15434
|
}
|
|
14640
15435
|
buildSessionDataUrl(path2, query) {
|
|
14641
15436
|
const searchParams = new URLSearchParams();
|
|
14642
|
-
|
|
14643
|
-
if (value !== null && typeof value !== "undefined" && value !== "") {
|
|
14644
|
-
searchParams.set(key, String(value));
|
|
14645
|
-
}
|
|
14646
|
-
}
|
|
15437
|
+
appendQueryOptions(searchParams, query);
|
|
14647
15438
|
const queryString = searchParams.toString();
|
|
14648
15439
|
return `${this.environment.runtimeBaseUrl}${this.sessionDataRoutePrefix}/${encodeURIComponent(this.sessionId)}${path2}${queryString ? `?${queryString}` : ""}`;
|
|
14649
15440
|
}
|
|
@@ -14726,9 +15517,108 @@ var EnvironmentSession = class extends Session {
|
|
|
14726
15517
|
),
|
|
14727
15518
|
get: (jobId) => this.sessionDataRequest(
|
|
14728
15519
|
`/jobs/${encodeURIComponent(jobId)}`
|
|
15520
|
+
),
|
|
15521
|
+
latest: async (options = {}) => {
|
|
15522
|
+
const page = await this.sessionDataRequest("/jobs", {
|
|
15523
|
+
status: options.status || "all",
|
|
15524
|
+
latest: true,
|
|
15525
|
+
limit: 1
|
|
15526
|
+
});
|
|
15527
|
+
return page.items[0] || null;
|
|
15528
|
+
}
|
|
15529
|
+
};
|
|
15530
|
+
}
|
|
15531
|
+
get artifacts() {
|
|
15532
|
+
return {
|
|
15533
|
+
list: (options = {}) => {
|
|
15534
|
+
const queryOptions = { ...options };
|
|
15535
|
+
if (options.target) {
|
|
15536
|
+
queryOptions.targetClassName = options.target.className;
|
|
15537
|
+
queryOptions.targetId = options.target.id;
|
|
15538
|
+
delete queryOptions.target;
|
|
15539
|
+
}
|
|
15540
|
+
return this.sessionDataRequest("/artifacts", queryOptions);
|
|
15541
|
+
},
|
|
15542
|
+
listForLatestJob: (options = {}) => this.artifacts.list({
|
|
15543
|
+
...options,
|
|
15544
|
+
latestJob: true
|
|
15545
|
+
}),
|
|
15546
|
+
get: (artifactId) => this.sessionDataRequest(
|
|
15547
|
+
`/artifacts/${encodeURIComponent(artifactId)}`
|
|
15548
|
+
),
|
|
15549
|
+
create: (artifact) => this.sessionDataRequest(
|
|
15550
|
+
"/artifacts",
|
|
15551
|
+
void 0,
|
|
15552
|
+
{
|
|
15553
|
+
method: "POST",
|
|
15554
|
+
body: artifact
|
|
15555
|
+
}
|
|
15556
|
+
),
|
|
15557
|
+
updateInputs: (artifactId, patch) => this.sessionDataRequest(
|
|
15558
|
+
`/artifacts/${encodeURIComponent(artifactId)}`,
|
|
15559
|
+
void 0,
|
|
15560
|
+
{
|
|
15561
|
+
method: "PATCH",
|
|
15562
|
+
body: patch
|
|
15563
|
+
}
|
|
15564
|
+
),
|
|
15565
|
+
validate: (artifactId) => this.sessionDataRequest(
|
|
15566
|
+
`/artifacts/${encodeURIComponent(artifactId)}/validate`,
|
|
15567
|
+
void 0,
|
|
15568
|
+
{ method: "POST" }
|
|
15569
|
+
),
|
|
15570
|
+
execute: (artifactId, options) => this.sessionDataRequest(
|
|
15571
|
+
`/artifacts/${encodeURIComponent(artifactId)}/execute`,
|
|
15572
|
+
void 0,
|
|
15573
|
+
{ method: "POST", body: options }
|
|
15574
|
+
),
|
|
15575
|
+
approve: (artifactId, options) => this.sessionDataRequest(
|
|
15576
|
+
`/artifacts/${encodeURIComponent(artifactId)}/approve`,
|
|
15577
|
+
void 0,
|
|
15578
|
+
{ method: "POST", body: options }
|
|
15579
|
+
),
|
|
15580
|
+
cancel: (artifactId) => this.sessionDataRequest(
|
|
15581
|
+
`/artifacts/${encodeURIComponent(artifactId)}/cancel`,
|
|
15582
|
+
void 0,
|
|
15583
|
+
{ method: "POST" }
|
|
14729
15584
|
)
|
|
14730
15585
|
};
|
|
14731
15586
|
}
|
|
15587
|
+
get manualActions() {
|
|
15588
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15589
|
+
return {
|
|
15590
|
+
record: (input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15591
|
+
"/manual-actions",
|
|
15592
|
+
void 0,
|
|
15593
|
+
{
|
|
15594
|
+
method: "POST",
|
|
15595
|
+
body: { ...input, sessionId: this.sessionId }
|
|
15596
|
+
}
|
|
15597
|
+
) : this.environment.manualActions.record({
|
|
15598
|
+
...input,
|
|
15599
|
+
sessionId: this.sessionId
|
|
15600
|
+
}),
|
|
15601
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/manual-actions", { ...options, sessionId: this.sessionId }) : this.environment.manualActions.list({
|
|
15602
|
+
...options,
|
|
15603
|
+
sessionId: this.sessionId
|
|
15604
|
+
}),
|
|
15605
|
+
suggest: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15606
|
+
"/manual-actions/suggestions",
|
|
15607
|
+
options
|
|
15608
|
+
) : this.environment.manualActions.suggest(options)
|
|
15609
|
+
};
|
|
15610
|
+
}
|
|
15611
|
+
get artifactApprovals() {
|
|
15612
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15613
|
+
return {
|
|
15614
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/artifact-approvals", options) : this.environment.artifactApprovals.list(options),
|
|
15615
|
+
decide: (approvalTaskId, input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15616
|
+
`/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
15617
|
+
void 0,
|
|
15618
|
+
{ method: "POST", body: input }
|
|
15619
|
+
) : this.environment.artifactApprovals.decide(approvalTaskId, input)
|
|
15620
|
+
};
|
|
15621
|
+
}
|
|
14732
15622
|
get files() {
|
|
14733
15623
|
return {
|
|
14734
15624
|
list: (options = {}) => this.sessionDataRequest(
|
|
@@ -14809,13 +15699,16 @@ var EnvironmentSession = class extends Session {
|
|
|
14809
15699
|
get transcript() {
|
|
14810
15700
|
return {
|
|
14811
15701
|
list: async (options = {}) => {
|
|
14812
|
-
const [messages, jobs, entries, lists] = await Promise.all([
|
|
15702
|
+
const [messages, jobs, entries, lists, artifacts] = await Promise.all([
|
|
14813
15703
|
this.collectAllSessionItems(this.messages.list),
|
|
14814
15704
|
this.collectAllSessionItems(
|
|
14815
15705
|
(pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
|
|
14816
15706
|
),
|
|
14817
15707
|
this.collectAllSessionItems(this.heap.entries.list),
|
|
14818
|
-
this.collectAllSessionItems(this.heap.lists.list)
|
|
15708
|
+
this.collectAllSessionItems(this.heap.lists.list),
|
|
15709
|
+
this.collectAllSessionItems(
|
|
15710
|
+
(pageOptions) => this.artifacts.list({ ...pageOptions, status: "all" })
|
|
15711
|
+
)
|
|
14819
15712
|
]);
|
|
14820
15713
|
const liveDoc = {
|
|
14821
15714
|
conversation: { messages },
|
|
@@ -14829,6 +15722,21 @@ var EnvironmentSession = class extends Session {
|
|
|
14829
15722
|
(entry) => Boolean(entry)
|
|
14830
15723
|
)
|
|
14831
15724
|
)
|
|
15725
|
+
},
|
|
15726
|
+
artifacts: {
|
|
15727
|
+
byId: Object.fromEntries(
|
|
15728
|
+
artifacts.map((artifact) => {
|
|
15729
|
+
return artifact?.artifactId ? [
|
|
15730
|
+
artifact.artifactId,
|
|
15731
|
+
artifact
|
|
15732
|
+
] : null;
|
|
15733
|
+
}).filter(
|
|
15734
|
+
(entry) => Boolean(entry)
|
|
15735
|
+
)
|
|
15736
|
+
),
|
|
15737
|
+
order: artifacts.map((artifact) => artifact?.artifactId).filter(
|
|
15738
|
+
(artifactId) => Boolean(artifactId)
|
|
15739
|
+
)
|
|
14832
15740
|
}
|
|
14833
15741
|
};
|
|
14834
15742
|
const heap = normalizeHeapSnapshot({
|
|
@@ -14905,6 +15813,12 @@ var EnvironmentSession = class extends Session {
|
|
|
14905
15813
|
async recordObject(options) {
|
|
14906
15814
|
return this.environment.recordObject(options);
|
|
14907
15815
|
}
|
|
15816
|
+
async recordState(input) {
|
|
15817
|
+
return this.environment.recordState(input);
|
|
15818
|
+
}
|
|
15819
|
+
state(target) {
|
|
15820
|
+
return this.environment.state(target);
|
|
15821
|
+
}
|
|
14908
15822
|
async recordObjects(records, options) {
|
|
14909
15823
|
return this.environment.recordObjects(records, options);
|
|
14910
15824
|
}
|
|
@@ -15732,15 +16646,43 @@ var Granular = class _Granular {
|
|
|
15732
16646
|
const effects = Array.from(
|
|
15733
16647
|
this.getSandboxEffectMap(host.sandboxId).values()
|
|
15734
16648
|
).map((effect) => this.serializeEffect(effect));
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
16649
|
+
let acceptedCount = 0;
|
|
16650
|
+
const rejected = [];
|
|
16651
|
+
try {
|
|
16652
|
+
await withTimeout(
|
|
16653
|
+
host.wsClient.call("effects.resetCatalog", {}),
|
|
16654
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16655
|
+
`effects.resetCatalog for sandbox ${host.sandboxId}`
|
|
16656
|
+
);
|
|
16657
|
+
for (const batch of chunkItems(effects, EFFECT_CATALOG_SYNC_BATCH_SIZE)) {
|
|
16658
|
+
const result = await withTimeout(
|
|
16659
|
+
host.wsClient.call("effects.addCatalog", {
|
|
16660
|
+
effects: batch
|
|
16661
|
+
}),
|
|
16662
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16663
|
+
`effects.addCatalog for sandbox ${host.sandboxId}`
|
|
16664
|
+
);
|
|
16665
|
+
acceptedCount += typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16666
|
+
if (Array.isArray(result?.rejected)) {
|
|
16667
|
+
rejected.push(...result.rejected);
|
|
16668
|
+
}
|
|
16669
|
+
}
|
|
16670
|
+
} catch (error) {
|
|
16671
|
+
if (!isUnsupportedEffectCatalogMutation(error)) {
|
|
16672
|
+
throw error;
|
|
16673
|
+
}
|
|
16674
|
+
const result = await withTimeout(
|
|
16675
|
+
host.wsClient.call("effects.publishCatalog", {
|
|
16676
|
+
effects
|
|
16677
|
+
}),
|
|
16678
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16679
|
+
`effects.publishCatalog for sandbox ${host.sandboxId}`
|
|
16680
|
+
);
|
|
16681
|
+
acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16682
|
+
if (Array.isArray(result?.rejected)) {
|
|
16683
|
+
rejected.push(...result.rejected);
|
|
16684
|
+
}
|
|
16685
|
+
}
|
|
15744
16686
|
if (acceptedCount === 0 && rejected.length > 0) {
|
|
15745
16687
|
const detail = rejected.map(
|
|
15746
16688
|
(entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`
|
|
@@ -16966,6 +17908,7 @@ var HARNESS_V3_FRONTEND_ACTIONS_MODULE = "@granular/actions/frontend";
|
|
|
16966
17908
|
var HARNESS_V3_CSV_MODULE = "@granular/utils/csv";
|
|
16967
17909
|
var HARNESS_V3_XLSX_MODULE = "@granular/utils/xlsx";
|
|
16968
17910
|
var LEGACY_SANDBOX_TOOLS_MODULE_PATTERN = "\\.\\/sandbox-tools(?:\\.js)?";
|
|
17911
|
+
var HARNESS_V3_RUNTIME_MODULE_PATTERN = "@granular/(?:agent|session|domain(?:/[A-Za-z_$][\\w$]*)?|actions/(?:backend|frontend)|utils/(?:csv|xlsx))";
|
|
16969
17912
|
function hasNamedModuleImport(source, moduleName, name) {
|
|
16970
17913
|
const escapedModule = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16971
17914
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -17024,6 +17967,15 @@ function reviewGeneratedJobCode(code, _options = {}) {
|
|
|
17024
17967
|
message: "Generated code must use static top-level ESM imports from the Harness v3 runtime modules. Do not use dynamic import(...)."
|
|
17025
17968
|
});
|
|
17026
17969
|
}
|
|
17970
|
+
if (new RegExp(
|
|
17971
|
+
`import\\s+\\*\\s+as\\s+[A-Za-z_$][\\w$]*\\s+from\\s*['"]${HARNESS_V3_RUNTIME_MODULE_PATTERN}['"]`
|
|
17972
|
+
).test(normalized)) {
|
|
17973
|
+
issues.push({
|
|
17974
|
+
code: "runtime_namespace_import",
|
|
17975
|
+
severity: "error",
|
|
17976
|
+
message: 'Generated code must use named imports from Harness runtime modules. Do not use namespace imports such as `import * as agent from "@granular/agent"`; use `import { replyToUser, artifacts } from "@granular/agent"`.'
|
|
17977
|
+
});
|
|
17978
|
+
}
|
|
17027
17979
|
if (/\bprocess\.exit\s*\(/.test(normalized)) {
|
|
17028
17980
|
issues.push({
|
|
17029
17981
|
code: "process_exit",
|
|
@@ -18043,6 +18995,31 @@ function buildGranularAgentHeapBlock(heapSummary) {
|
|
|
18043
18995
|
entries: {}
|
|
18044
18996
|
});
|
|
18045
18997
|
}
|
|
18998
|
+
function buildGranularAgentManualActionMemorySummary(input) {
|
|
18999
|
+
const maxItems = Math.max(1, Math.min(12, input.maxItems ?? 8));
|
|
19000
|
+
const suggestions = (input.suggestions || []).filter((suggestion) => suggestion?.actionKey).slice(0, maxItems).map((suggestion) => ({
|
|
19001
|
+
actionKey: suggestion.actionKey,
|
|
19002
|
+
label: suggestion.label || null,
|
|
19003
|
+
targetClassName: suggestion.targetClassName || null,
|
|
19004
|
+
count: typeof suggestion.count === "number" && Number.isFinite(suggestion.count) ? suggestion.count : null,
|
|
19005
|
+
subjectCount: typeof suggestion.subjectCount === "number" && Number.isFinite(suggestion.subjectCount) ? suggestion.subjectCount : null,
|
|
19006
|
+
successCount: typeof suggestion.successCount === "number" && Number.isFinite(suggestion.successCount) ? suggestion.successCount : null,
|
|
19007
|
+
failureCount: typeof suggestion.failureCount === "number" && Number.isFinite(suggestion.failureCount) ? suggestion.failureCount : null,
|
|
19008
|
+
lastOccurredAt: typeof suggestion.lastOccurredAt === "number" && Number.isFinite(suggestion.lastOccurredAt) ? suggestion.lastOccurredAt : null,
|
|
19009
|
+
sampleTargetIds: Array.isArray(suggestion.sampleTargetIds) ? suggestion.sampleTargetIds.filter(
|
|
19010
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
19011
|
+
).slice(0, 6) : []
|
|
19012
|
+
}));
|
|
19013
|
+
return [
|
|
19014
|
+
renderConstBlock("manualActionMemory", {
|
|
19015
|
+
suggestions
|
|
19016
|
+
}),
|
|
19017
|
+
"Use manualActionMemory only as behavioral context for likely next actions. Ground the current target and validate permissions before creating or running prepared actions."
|
|
19018
|
+
].join("\n");
|
|
19019
|
+
}
|
|
19020
|
+
function buildGranularAgentManualActionBlock(manualActionSummary) {
|
|
19021
|
+
return manualActionSummary?.trim() || buildGranularAgentManualActionMemorySummary({ suggestions: [] });
|
|
19022
|
+
}
|
|
18046
19023
|
function projectSessionFileSummary(liveDoc) {
|
|
18047
19024
|
const files = asRecord4(liveDoc?.files);
|
|
18048
19025
|
const byId = asRecord4(files?.byId) || {};
|
|
@@ -18074,8 +19051,12 @@ function buildGranularAgentFileBlock(fileSummary) {
|
|
|
18074
19051
|
function extractRuntimeContractExports(domainBlock) {
|
|
18075
19052
|
const classes = /* @__PURE__ */ new Set();
|
|
18076
19053
|
const actions = /* @__PURE__ */ new Set();
|
|
18077
|
-
const
|
|
18078
|
-
for (const match of domainBlock.matchAll(
|
|
19054
|
+
const classConstPattern = /export\s+declare\s+const\s+([A-Za-z_$][\w$]*)\s*:\s*EntityClass\b/g;
|
|
19055
|
+
for (const match of domainBlock.matchAll(classConstPattern)) {
|
|
19056
|
+
classes.add(match[1]);
|
|
19057
|
+
}
|
|
19058
|
+
const classDeclPattern = /export\s+declare\s+class\s+([A-Za-z_$][\w$]*)\b/g;
|
|
19059
|
+
for (const match of domainBlock.matchAll(classDeclPattern)) {
|
|
18079
19060
|
classes.add(match[1]);
|
|
18080
19061
|
}
|
|
18081
19062
|
const actionPattern = /export\s+declare\s+function\s+([A-Za-z_$][\w$]*)/g;
|
|
@@ -18580,6 +19561,9 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18580
19561
|
});
|
|
18581
19562
|
const referentBlock = buildGranularAgentReferentBlock(input.referentSummary);
|
|
18582
19563
|
const loopBlock = buildGranularAgentLoopBlock(input.loopSummary);
|
|
19564
|
+
const manualActionBlock = buildGranularAgentManualActionBlock(
|
|
19565
|
+
input.manualActionSummary
|
|
19566
|
+
);
|
|
18583
19567
|
const knownFactsBlock = renderConstBlock(
|
|
18584
19568
|
"knownFacts",
|
|
18585
19569
|
buildKnownFactsFromCheckpoint(input.checkpoint)
|
|
@@ -18593,16 +19577,15 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18593
19577
|
- \`replyToUser(...)\` displays text directly to the user in the host UI. Treat it as the user-facing progress and reply channel, not as a debug log.
|
|
18594
19578
|
- For long-running or multi-step jobs, send several short \`replyToUser(...)\` updates as useful milestones are reached so the user can see what is happening instead of waiting in silence.
|
|
18595
19579
|
- Write \`replyToUser(...)\` content in a friendly, readable product-assistant style: concrete, concise, and natural. Avoid robotic status dumps, raw implementation names, and unexplained IDs unless the ID helps the user.
|
|
18596
|
-
- When \`replyToUser(...)\` mentions a grounded record that should remain clickable/referable, wrap only the visible record label in a self-closing inline reference tag
|
|
18597
|
-
- Treat \`showObjects(...)\` as the UI display call for user-visible records,
|
|
18598
|
-
-
|
|
18599
|
-
-
|
|
18600
|
-
-
|
|
18601
|
-
-
|
|
19580
|
+
- When \`replyToUser(...)\` mentions a grounded record that should remain clickable/referable, wrap only the visible record label in a self-closing inline reference tag using the actual class name and id/path.
|
|
19581
|
+
- Treat \`showObjects(...)\` as the UI display call for user-visible records. When records should remain reusable for follow-ups, first save the runtime record or ordered record array with \`await groundedObjects.save("stable_selection_name", value)\`, then display it once with \`showObjects({ variableNames: ["stable_selection_name"] })\`.
|
|
19582
|
+
- \`groundedObjects.save(...)\` only accepts scalar values, session files, runtime records/sandbox instances, or arrays of runtime records/sandbox instances from one class. Do not save plain action/effect result objects; fetch affected records first or answer from summaries with \`replyToUser(...)\`.
|
|
19583
|
+
- Do not use \`showObjects({ entries: [...] })\` or \`showObjects({ saveAs, entries })\`. Save ordered pages, queues, search results, or ranked lists with \`groundedObjects.save(...)\`, then call \`showObjects({ variableNames: [...] })\` once.
|
|
19584
|
+
- Use \`showAgentResponse({ reply, show: [record, action] })\` when one assistant message should combine text, grounded records, files, prepared actions, or action suggestions. The \`action\` can be a state handle such as \`record.lifecycle.approved\` or an action handle such as \`record.lifecycle.approved.reach()\`.
|
|
19585
|
+
- Do not use deprecated side-channel helpers such as \`agent_text_message(...)\`, \`agent_heap_objects(...)\`, or \`agent_message(...)\` unless the generated types expose no Harness v3 helper alternative.
|
|
18602
19586
|
- When the user asks to show, list, display, open, or "show them" for records you found, call \`showObjects(...)\`; do not answer only with a count or text summary.
|
|
18603
19587
|
- For count-only questions such as "how many", "how many X do I have", or "what is the total number of X", call the entity \`.count(...)\` or use page \`totalCount\` only when a page is already needed for other reasons. Answer with \`replyToUser(...)\` only. Do not call \`showObjects(...)\`, \`saveAs\`, or \`groundedObjects.save(...)\` unless the user also asked to see records or a later requested action needs a reusable record selection.
|
|
18604
|
-
-
|
|
18605
|
-
- For ordered record slices, pages, queues, search results, or ranked lists, save the slice with \`groundedObjects.save(...)\` and then call \`showObjects({ variableNames: [...] })\` once. Use a stable name that preserves the slice identity and ordering so later references such as "the second item" or "back on the first slice" resolve to the correct earlier slice, not merely the most recent record.
|
|
19588
|
+
- Use stable saved list names that preserve identity and ordering so later references such as "the second item" or "back on the first slice" resolve to the correct earlier slice, not merely the most recent record.
|
|
18606
19589
|
- Do not rely on the final return value for UI output. Do not return ad-hoc \`reply\` / \`show\` payloads instead of explicit agent message calls.` : `- Every job that answers the user must emit \`replyToUser(...)\` from \`@granular/agent\`.
|
|
18607
19590
|
- \`replyToUser(...)\` displays text directly to the user in the host UI. Treat it as the user-facing progress and reply channel, not as a debug log.
|
|
18608
19591
|
- For long-running or multi-step jobs, send several short \`replyToUser(...)\` updates as useful milestones are reached so the user can see what is happening instead of waiting in silence.
|
|
@@ -18613,7 +19596,7 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18613
19596
|
- When using code, assistant text must be empty or one brief summary.
|
|
18614
19597
|
- Code must be plain runnable JavaScript with top-level await.
|
|
18615
19598
|
- Use [Runtime Imports] as the authoritative module map. Import only listed module exports.
|
|
18616
|
-
- Use static top-level imports such as \`import { Foo } from "@granular/domain/Foo"; import { replyToUser } from "@granular/agent";\`. Do not use dynamic imports for runtime modules.
|
|
19599
|
+
- Use static top-level named imports such as \`import { Foo } from "@granular/domain/Foo"; import { replyToUser, artifacts } from "@granular/agent";\`. Do not use dynamic imports or namespace imports like \`import * as agent from "@granular/agent"\` for runtime modules.
|
|
18617
19600
|
- Read and write session files through the virtual filesystem modules listed in [Runtime Imports]. Input files are mounted under \`/session/input\`; files written under \`/session/output\` are persisted as agent-created session files.
|
|
18618
19601
|
- Do not ask the user to provide virtual filesystem paths. Users attach or mention files by name in the UI; resolve the right file from \`sessionFileManifest.files\` or the current attachment context, then use its provided path internally.
|
|
18619
19602
|
- The \`sessionFileManifest\` block is prompt context, not an imported module or runtime variable. For dynamic file lookup, import \`files\` from \`@granular/session\` and match \`filename\` to a returned file's \`path\`.
|
|
@@ -18676,6 +19659,7 @@ ${workflowRules}
|
|
|
18676
19659
|
High-priority execution rules:
|
|
18677
19660
|
- Treat a human reference as something to ground, not as missing data. When the user names or describes a record, group, queue, parent, relationship, or prior result and asks to inspect, decide, update, schedule, approve, send, or otherwise act on session data, run a code job to ground it before asking the user for more details.
|
|
18678
19661
|
- For a human-described primary anchor, a no-match answer is only justified after more than one distinct grounding attempt, such as owner/container grounding, relationship traversal, exact id/path lookup, or shorter target-local search. Before the primary no-match return, retry that same anchor with fewer text constraints or a distinct grounding strategy; do not stop after one zero-result list/find/page call.
|
|
19662
|
+
- If the latest user wording names an entity type that has an importable class, ground that class first. A previously installed parent class or related action method is not a substitute; after zero results in one class, pivot to the latest named importable class before reporting no match.
|
|
18679
19663
|
- A confirmation requirement is not a reason to stay text-only. Do all safe read-only grounding and availability/status checks first, then call \`userInteraction.askConfirmation(...)\` or \`userInteraction.askChoice(...)\` before the mutation.
|
|
18680
19664
|
- In any code branch where a requested action or mutation has multiple possible targets, import \`userInteraction\` from \`@granular/session\` and use \`await userInteraction.askChoice(...)\` in that branch. This includes ambiguity discovered after a query returns several records. A branch that only shows candidates, asks in text, and returns leaves the requested action unfinished.
|
|
18681
19665
|
- Before any mutation, know whether the target is one record or several. A singular phrase like "the item" is not proof of uniqueness after a query finds multiple matching records. If the user did not give an exact identifier or explicit selection criterion, call \`userInteraction.askChoice({ options, ... })\` with grounded choices; do not choose by age, amount, priority, order, or convenience on your own. Resolve the target before any yes/no confirmation.
|
|
@@ -18719,7 +19703,7 @@ Intent resolution:
|
|
|
18719
19703
|
- For follow-up words like "other", "another", or "remaining" after the user selected one candidate from a previous choice, resolve within the active contrast from that choice and the user's answer. Exclude the selected item, preserve descriptors such as larger, smaller, next, older, different, or same status, and do not take the first leftover from a wider saved list when the contrast narrows the intended set.
|
|
18720
19704
|
- Before any mutation, prove the target resolves to exactly one grounded record. If the request describes a set, category, relationship, prior result group, or other non-unique scope, gather the candidate records first; when more than one candidate remains, ask the user to choose before calling the action.
|
|
18721
19705
|
- For ambiguous choice prompts before a mutation, every option that describes a different candidate must carry a distinct grounded record value/path. After the answer, do not fall back to the first candidate if matching fails; ask again or stop without mutating.
|
|
18722
|
-
- The [State] constants and [Runtime Imports] map are prompt context, not runtime variables. Never reference \`runtimeImports\`, \`savedData\`, \`sessionFileManifest\`, \`recentReferences\`, \`workflowContext\`, \`workflowState\`, or \`capabilities\` as variables in generated code. When using a recent reference or file path, copy
|
|
19706
|
+
- The [State] constants and [Runtime Imports] map are prompt context, not runtime variables. Never reference \`runtimeImports\`, \`savedData\`, \`manualActionMemory\`, \`sessionFileManifest\`, \`recentReferences\`, \`workflowContext\`, \`workflowState\`, or \`capabilities\` as variables in generated code. When using a recent reference, manual-action pattern, or file path, copy concrete ids/values into code and fetch/read it with the relevant runtime API.
|
|
18723
19707
|
- Never write placeholder grounding code such as \`const path = null\`, \`const groundedPath = ""\`, or \`const recordPath = ""\`. If no saved reference is available, delete that branch entirely and execute the fallback lookup directly.
|
|
18724
19708
|
- Never call \`.get({ path: "" })\`; an empty path is not a saved reference.
|
|
18725
19709
|
- For ordinal references to earlier pages, slices, lists, or ranked results, use the saved list/recent references first. If no saved list is available, rerun the exact same ordered query and select the ordinal index from its returned \`items\`; never invent a record path from a label or ordinal.
|
|
@@ -18846,20 +19830,10 @@ Ask the user when:
|
|
|
18846
19830
|
- the target is unique but the requested action is unclear
|
|
18847
19831
|
|
|
18848
19832
|
Relationship filters:
|
|
18849
|
-
-
|
|
18850
|
-
-
|
|
18851
|
-
-
|
|
18852
|
-
-
|
|
18853
|
-
- Do not invent nested operators under relationship fields. A one-record relationship filter accepts only its documented operators such as \`id\`, \`path\`, \`is\`, \`null\`, and \`not_null\`; deeper conditions must go under \`is\` or be handled by fetching records and following getters.
|
|
18854
|
-
- Never use \`some\` on one-record fields. If the generated TypeScript type says \`OneRelationFilter\`, valid operators are \`id\`, \`path\`, \`is\`, \`null\`, and \`not_null\`; \`some\` is invalid.
|
|
18855
|
-
- Use \`some\` only when the generated TypeScript type says \`ManyRelationFilter\`.
|
|
18856
|
-
- For a singular relationship that points to an intermediate record, nested filters still use \`is\` at the singular hop. Do not use \`some\` because the nested condition names another related record.
|
|
18857
|
-
- Use \`{ relationship: { id: "record_id" } }\` or \`{ relationship: { path: "class_record_id" } }\` when matching a known related record.
|
|
18858
|
-
- When you already fetched the related record, use \`{ relationship: { path: record._graphPath } }\` or \`{ relationship: { id: record.id } }\`; do not wrap a known id/path under \`is\`.
|
|
18859
|
-
- The path used in a relationship filter must be the path of the relationship target. For same-queue follow-ups from an item/batch/ticket, fetch that item's related unit/site/depot first and use the related unit/site/depot path; do not use the item path as a unit/site/depot path.
|
|
18860
|
-
- Use \`{ relationship: { is: { field: { equal_to: value } } } }\` only for nested field filters. Never put \`id\` or \`path\` inside \`is\`.
|
|
18861
|
-
- Do not write \`{ relationship: { some: ... } }\` unless the generated filter type for that exact relationship says it is a many/collection relationship. For one-record, parent, owner, or many-to-one relationships, use \`path\`, \`id\`, \`is\`, or getter traversal.
|
|
18862
|
-
- Do not pass a full record instance into a filter; if you already fetched a record, filter by its id or path instead.
|
|
19833
|
+
- Use the generated filter type as the authority: \`OneRelationFilter\` supports \`id\`, \`path\`, \`is\`, \`null\`, \`not_null\`; \`ManyRelationFilter\` supports those plus \`some\`.
|
|
19834
|
+
- Use \`id\` or \`path\` for a known related record; use \`is\` or \`some\` only for nested target-field filters.
|
|
19835
|
+
- Relationship paths must belong to the relationship target type. If you have a parent/container/item of another type, fetch the declared related record first and filter with that related record's id/path.
|
|
19836
|
+
- Never pass a full record instance into a filter. Use its id/path or a declared relationship getter.
|
|
18863
19837
|
${domainSections.docs ? `
|
|
18864
19838
|
Domain notes:
|
|
18865
19839
|
${domainSections.docs}
|
|
@@ -18870,6 +19844,23 @@ ${actionIndex}
|
|
|
18870
19844
|
- Global backend actions are executable functions exported by \`@granular/actions/backend\`; import each backend action you call, e.g. \`import { some_action } from "@granular/actions/backend"; await some_action(...)\`. Frontend actions are exported by \`@granular/actions/frontend\` when the action index marks them as frontend actions.
|
|
18871
19845
|
- Actions listed under "Record-level" are instance methods. First fetch or find the specific record, then call the action on that instance, e.g. \`const item = await Item.get({ path }); await item.action_name(...)\`.
|
|
18872
19846
|
- Actions listed under "Class-level" are class/static methods. Call them on the imported class, e.g. \`await Item.action_name(...)\`.
|
|
19847
|
+
- State-machine handles are the preferred workflow surface. For an existing record, use \`record.lifecycle.targetState\`; for a not-yet-created record, use class-level handles such as \`SpendRequest.lifecycle.policy_review\` only to prepare a provisional new-record action flow.
|
|
19848
|
+
- For pure field-collection requests, target the class-level entry state handle; for submit/review requests, target the nearest requested later state.
|
|
19849
|
+
- Choose the nearest target state that matches the user's words. Do not aim at a later state just because it is reachable.
|
|
19850
|
+
- For grounded stateful records, choose the target state handle from the user's requested outcome and handle docs. Use \`plan()\`, \`blockers()\`, or \`permissions()\` to explain reachability, missing requirements, stale state, and who can run the action; do not derive workflow meaning or adjacent actions from raw \`record.status\` or \`current().state\`.
|
|
19851
|
+
- Before opening a stateful action, call \`const plan = await handle.plan()\`. If the plan or opened artifact shows blockers, stale state, missing relationships, permissions, or no reachable path, explain those structured results and display the record/artifact. Do not skip to a later state or build your own status ladder.
|
|
19852
|
+
- Use typed plan fields and helpers directly. For visible blocker text, use the declared blocker-formatting helper when available instead of hand-written object casts.
|
|
19853
|
+
- A suggestion is a recommendation button: \`await stateHandle.suggest(message)\`. A prepared action is the editable form the user can review/run: \`const action = stateHandle.reach(); const prepared = await action.open()\`.
|
|
19854
|
+
- 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.
|
|
19855
|
+
- Open a prepared action when the user asks for one clear action. Prefill only values grounded in the user request, conversation, files, selected records, or fresh reads. Leave unknown fields empty; do not invent them.
|
|
19856
|
+
- 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.
|
|
19857
|
+
- A derived intermediate relationship is not enough when another required relationship is still reachable from it. For example, if a team gives a cost center and the action also requires a budget, traverse the cost center's declared budget relationship before opening the action.
|
|
19858
|
+
- If the user says they have a document/work item/event but no matching record is found, check for a declared class-level new-record state/action handle or importable backend create/preparation action for that named class before giving up. Use grounded required fields to open the prepared action or call the create/preparation action; if required values are still missing and no prepared action can collect them, ask only for those values. Do not claim the record already exists.
|
|
19859
|
+
- Do not ask for confirmation before opening a prepared action. The prepared action is itself reviewable. Use \`userInteraction.askConfirmation\` only when the user explicitly asks for yes/no approval, the selected action is ambiguous after grounding, or the domain/runtime asks for confirmation.
|
|
19860
|
+
- If the action cannot continue because of missing input, stale state, missing relationships, related-state requirements, or permissions, keep/show the prepared action at that blocker and explain the next needed person, record, or value. Do not skip workflow steps or target a later state.
|
|
19861
|
+
- Reuse an already-open prepared action for the same target/action when available: update it, show it again, or explain what is still needed instead of creating a duplicate.
|
|
19862
|
+
- If an open prepared action needs edits, prefer the returned record helper: \`const prepared = await action.open(); await prepared.updateInputs({ inputValues, relationships });\`. Use \`artifacts.updateInputs(id, patch)\` only when you only have an id.
|
|
19863
|
+
- Use \`await prepared.show()\` or \`await actions.show(prepared)\` only to display an already-created prepared action again.
|
|
18873
19864
|
- The action index is the visibility contract. If an action is listed for a class, call it directly on fetched/listed instances of that class; do not use \`typeof record.action_name === "function"\` as a discovery gate. If an action is not listed, do not call it.
|
|
18874
19865
|
- Never call a record-level action as \`Class.action_name(...)\`; that method will not exist.
|
|
18875
19866
|
- For action inputs, use the exact property names from the generated TypeScript method signature or the input schema shown in the action list. Do not invent synonym fields for required inputs.
|
|
@@ -18900,6 +19891,8 @@ ${loopBlock}
|
|
|
18900
19891
|
|
|
18901
19892
|
${knownFactsBlock}
|
|
18902
19893
|
|
|
19894
|
+
${manualActionBlock}
|
|
19895
|
+
|
|
18903
19896
|
[Request]
|
|
18904
19897
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
18905
19898
|
}
|
|
@@ -19650,6 +20643,8 @@ function modelOutputInstruction() {
|
|
|
19650
20643
|
'Do not use "action":"reply" to say a record is not grounded yet; if the request names or describes a domain record, use "action":"job" and ground it from session state, relationships, searches, or visible read-only actions first.',
|
|
19651
20644
|
'Before claiming you lack access, inspect the visible action list. If a visible read-only search, lookup, list, guidance, note, policy, or knowledge action can satisfy a "check", "find", "look up", or "whether we have guidance" request, choose "action":"job" and call it.',
|
|
19652
20645
|
"Generated code must not report no matches for the primary human-described anchor after a single zero-result list/find/page call. Before that primary no-match return, retry the primary anchor with fewer text constraints or a distinct fallback such as owner/container grounding, relationship traversal, exact-id/path lookup, or shorter target-local search.",
|
|
20646
|
+
"If the latest request names an importable entity type, generated code must ground that class first; a previously installed parent class or related action method is not a substitute. After zero results in one class, pivot to the latest named importable class before reporting no match.",
|
|
20647
|
+
"When the user says they have a document/work item/event but no matching record exists yet, generated code must check the visible class-level new-record/create/preparation surface before returning no-match; if required create inputs are still missing and no prepared action can collect them, ask only for those inputs.",
|
|
19653
20648
|
'Use "action":"job" when the next step should run code or mutate workflow state.',
|
|
19654
20649
|
'When action is "job", include runnable code in "code" and emit the "code" field before any non-empty "reply" field so generated code comments can stream as progress.',
|
|
19655
20650
|
"Generated job code must use plain ASCII punctuation in string literals and comments. Do not use curly quotes, smart apostrophes, en dashes, em dashes, or other typographic punctuation in code.",
|
|
@@ -19719,7 +20714,12 @@ function createOpenAIChatTurnGenerator(options) {
|
|
|
19719
20714
|
|
|
19720
20715
|
${modelOutputInstruction()}`
|
|
19721
20716
|
},
|
|
19722
|
-
...input.history
|
|
20717
|
+
...input.history.map(
|
|
20718
|
+
(message) => ({
|
|
20719
|
+
role: message.role,
|
|
20720
|
+
content: message.content
|
|
20721
|
+
})
|
|
20722
|
+
),
|
|
19723
20723
|
{ role: "user", content: input.request }
|
|
19724
20724
|
];
|
|
19725
20725
|
const payload = {
|
|
@@ -19738,11 +20738,12 @@ ${modelOutputInstruction()}`
|
|
|
19738
20738
|
let usage = null;
|
|
19739
20739
|
let requestId = null;
|
|
19740
20740
|
if (input.onTextDelta || input.onReplyDelta || input.onCodeDelta) {
|
|
19741
|
-
const
|
|
20741
|
+
const streamPayload = {
|
|
19742
20742
|
...payload,
|
|
19743
20743
|
stream: true,
|
|
19744
20744
|
stream_options: { include_usage: true }
|
|
19745
|
-
}
|
|
20745
|
+
};
|
|
20746
|
+
const stream = await client.chat.completions.create(streamPayload);
|
|
19746
20747
|
let streamedReply = "";
|
|
19747
20748
|
let streamedCode = "";
|
|
19748
20749
|
const emitReplyDelta = async () => {
|
|
@@ -19768,7 +20769,8 @@ ${modelOutputInstruction()}`
|
|
|
19768
20769
|
await input.onCodeDelta(delta);
|
|
19769
20770
|
};
|
|
19770
20771
|
for await (const event of stream) {
|
|
19771
|
-
|
|
20772
|
+
const eventRecord = event;
|
|
20773
|
+
requestId = requestId || event.id || (typeof eventRecord._request_id === "string" ? eventRecord._request_id : null);
|
|
19772
20774
|
usage = event.usage || usage;
|
|
19773
20775
|
const delta = event.choices?.[0]?.delta?.content;
|
|
19774
20776
|
const deltaText = typeof delta === "string" ? delta : Array.isArray(delta) ? delta.map((part) => asRecord6(part)?.text || "").join("") : "";
|
|
@@ -19782,14 +20784,13 @@ ${modelOutputInstruction()}`
|
|
|
19782
20784
|
await emitCodeDelta();
|
|
19783
20785
|
raw = { streamed: true, model, usage, request_id: requestId };
|
|
19784
20786
|
} else {
|
|
19785
|
-
const completion = await client.chat.completions.create(
|
|
19786
|
-
|
|
19787
|
-
);
|
|
20787
|
+
const completion = await client.chat.completions.create(payload);
|
|
20788
|
+
const completionRecord = completion;
|
|
19788
20789
|
raw = completion;
|
|
19789
20790
|
usage = completion.usage;
|
|
19790
|
-
requestId = (typeof completion.id === "string" ? completion.id : null) || (typeof
|
|
20791
|
+
requestId = (typeof completion.id === "string" ? completion.id : null) || (typeof completionRecord._request_id === "string" ? completionRecord._request_id : null);
|
|
19791
20792
|
const content = asRecord6(
|
|
19792
|
-
asRecord6(completion.choices
|
|
20793
|
+
asRecord6(completion.choices[0])?.message
|
|
19793
20794
|
)?.content;
|
|
19794
20795
|
text = typeof content === "string" ? content : Array.isArray(content) ? content.map((part) => asRecord6(part)?.text || "").join("") : "";
|
|
19795
20796
|
}
|
|
@@ -20126,6 +21127,9 @@ async function generateTurnWithRepair(generator, input) {
|
|
|
20126
21127
|
"",
|
|
20127
21128
|
"The previous generated job code failed preflight review against [Runtime Imports] and the runtime contract.",
|
|
20128
21129
|
"Return a corrected JSON object. Keep the user's requested behavior, but fix every issue below before execution.",
|
|
21130
|
+
"If an issue says workflow path, blockers, permissions, or readiness were derived from raw status fields, remove the status/current-state ladder. Pick the declared state handle that matches the user's requested outcome, call plan()/blockers()/permissions() first, then open/show that handle or explain its structured blockers.",
|
|
21131
|
+
"If an issue says an unsafe type assertion was used, remove the cast and use declared fields or typed helpers directly. For state plans, use plan.blockers, plan.permissions, plan.steps, plan.summary, or blocker-formatting helpers without hand-written object casts.",
|
|
21132
|
+
"If the previous code stopped after no matching record for a user-supplied document/work item, preserve the lookup but check declared new-record/create/preparation surfaces next. Import the backend action module if needed, or ask only for missing required create inputs when no prepared action can collect them.",
|
|
20129
21133
|
"",
|
|
20130
21134
|
"Preflight issues:",
|
|
20131
21135
|
...issues.map((issue) => `- ${issue.code}: ${issue.message}`),
|