@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/index.mjs
CHANGED
|
@@ -4016,6 +4016,9 @@ function rpcTimeoutMsForMethod(method) {
|
|
|
4016
4016
|
return DOMAIN_PACKAGE_RPC_TIMEOUT_MS;
|
|
4017
4017
|
case "client.heartbeat":
|
|
4018
4018
|
case "effects.publishCatalog":
|
|
4019
|
+
case "effects.resetCatalog":
|
|
4020
|
+
case "effects.addCatalog":
|
|
4021
|
+
case "effects.removeCatalog":
|
|
4019
4022
|
case "effects.refresh":
|
|
4020
4023
|
return EFFECT_CONTROL_RPC_TIMEOUT_MS;
|
|
4021
4024
|
case "harness.run":
|
|
@@ -4761,6 +4764,9 @@ function resolvePromptAnswer(prompt, answer) {
|
|
|
4761
4764
|
|
|
4762
4765
|
// src/session.ts
|
|
4763
4766
|
var PROMPT_TRANSCRIPT_APPEND_TIMEOUT_MS = 5e3;
|
|
4767
|
+
function toPascalCase(value) {
|
|
4768
|
+
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
4769
|
+
}
|
|
4764
4770
|
function withPromptTranscriptTimeout(promise) {
|
|
4765
4771
|
let timeout = null;
|
|
4766
4772
|
return Promise.race([
|
|
@@ -5323,9 +5329,7 @@ var Session = class {
|
|
|
5323
5329
|
if (classes && Object.keys(classes).length > 0) {
|
|
5324
5330
|
let docs2 = "# Domain Documentation\n\n";
|
|
5325
5331
|
docs2 += "Import concrete classes from `@granular/domain/<Class>` and global backend actions from `@granular/actions/backend`:\n\n";
|
|
5326
|
-
const classNames = Object.keys(classes).map(
|
|
5327
|
-
(c) => c.charAt(0).toUpperCase() + c.slice(1)
|
|
5328
|
-
);
|
|
5332
|
+
const classNames = Object.keys(classes).map(toPascalCase);
|
|
5329
5333
|
const globalNames = (globalTools || []).map((t) => t.name);
|
|
5330
5334
|
const importLines = [
|
|
5331
5335
|
...classNames.map(
|
|
@@ -5339,7 +5343,7 @@ ${importLines.join("\n") || "// No generated domain imports available."}
|
|
|
5339
5343
|
|
|
5340
5344
|
`;
|
|
5341
5345
|
for (const [className, cls] of Object.entries(classes)) {
|
|
5342
|
-
const TsName =
|
|
5346
|
+
const TsName = toPascalCase(className);
|
|
5343
5347
|
docs2 += `## ${TsName}
|
|
5344
5348
|
|
|
5345
5349
|
`;
|
|
@@ -6329,6 +6333,28 @@ function asString(value) {
|
|
|
6329
6333
|
function trimString(value) {
|
|
6330
6334
|
return typeof value === "string" ? value.trim() : "";
|
|
6331
6335
|
}
|
|
6336
|
+
function compactJson(value, maxLength = 320) {
|
|
6337
|
+
if (value === void 0 || value === null) return void 0;
|
|
6338
|
+
try {
|
|
6339
|
+
const json = JSON.stringify(value);
|
|
6340
|
+
if (!json || json === "undefined") return void 0;
|
|
6341
|
+
return json.length > maxLength ? `${json.slice(0, maxLength)}...` : json;
|
|
6342
|
+
} catch {
|
|
6343
|
+
return String(value);
|
|
6344
|
+
}
|
|
6345
|
+
}
|
|
6346
|
+
function artifactRecordsById(liveDoc) {
|
|
6347
|
+
const artifacts = asRecord3(liveDoc?.artifacts);
|
|
6348
|
+
const byId = asRecord3(artifacts?.byId) || {};
|
|
6349
|
+
return Object.fromEntries(
|
|
6350
|
+
Object.entries(byId).map(([artifactId, value]) => {
|
|
6351
|
+
const record = asRecord3(value);
|
|
6352
|
+
return record ? [artifactId, record] : null;
|
|
6353
|
+
}).filter(
|
|
6354
|
+
(entry) => Boolean(entry)
|
|
6355
|
+
)
|
|
6356
|
+
);
|
|
6357
|
+
}
|
|
6332
6358
|
function normalizeShowRefs(value) {
|
|
6333
6359
|
const record = asRecord3(value);
|
|
6334
6360
|
if (!record) return void 0;
|
|
@@ -6345,9 +6371,31 @@ function normalizeShowRefs(value) {
|
|
|
6345
6371
|
entryPaths: normalizeRefs(record.entryPaths),
|
|
6346
6372
|
listNames: normalizeRefs(record.listNames),
|
|
6347
6373
|
variableNames: normalizeRefs(record.variableNames),
|
|
6348
|
-
fileIds: normalizeRefs(record.fileIds)
|
|
6374
|
+
fileIds: normalizeRefs(record.fileIds),
|
|
6375
|
+
sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
|
|
6376
|
+
actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
|
|
6349
6377
|
};
|
|
6350
|
-
return show.entryPaths || show.listNames || show.variableNames || show.fileIds ? show : void 0;
|
|
6378
|
+
return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions ? show : void 0;
|
|
6379
|
+
}
|
|
6380
|
+
function normalizeActionSuggestions(value) {
|
|
6381
|
+
if (!Array.isArray(value)) return void 0;
|
|
6382
|
+
const suggestions = [];
|
|
6383
|
+
for (const item of value) {
|
|
6384
|
+
const record = asRecord3(item);
|
|
6385
|
+
if (!record) continue;
|
|
6386
|
+
const label = trimString(record.label);
|
|
6387
|
+
if (!label) continue;
|
|
6388
|
+
const suggestionId = trimString(record.suggestionId) || trimString(record.id) || label;
|
|
6389
|
+
suggestions.push({
|
|
6390
|
+
suggestionId,
|
|
6391
|
+
label,
|
|
6392
|
+
...typeof record.description === "string" ? { description: record.description } : {},
|
|
6393
|
+
...asRecord3(record.artifact) ? { artifact: asRecord3(record.artifact) } : {},
|
|
6394
|
+
...asRecord3(record.target) ? { target: asRecord3(record.target) } : {},
|
|
6395
|
+
...asRecord3(record.metadata) ? { metadata: asRecord3(record.metadata) } : {}
|
|
6396
|
+
});
|
|
6397
|
+
}
|
|
6398
|
+
return suggestions.length ? suggestions : void 0;
|
|
6351
6399
|
}
|
|
6352
6400
|
function stringifyTranscriptValue(value, fallback = "") {
|
|
6353
6401
|
if (typeof value === "string") {
|
|
@@ -6367,12 +6415,139 @@ function stringifyTranscriptValue(value, fallback = "") {
|
|
|
6367
6415
|
return String(value);
|
|
6368
6416
|
}
|
|
6369
6417
|
}
|
|
6370
|
-
function
|
|
6418
|
+
function latestInputEditSummary(metadata) {
|
|
6419
|
+
const lastInputEdit = asRecord3(metadata.lastInputEdit);
|
|
6420
|
+
if (!lastInputEdit) return null;
|
|
6421
|
+
const source = asString(lastInputEdit.source) || "unknown";
|
|
6422
|
+
const actor = asString(lastInputEdit.actorSubjectId) || asString(lastInputEdit.actorPermissionProfileName) || asString(lastInputEdit.jobId) || null;
|
|
6423
|
+
const inputKeys = Array.isArray(lastInputEdit.changedInputKeys) ? lastInputEdit.changedInputKeys.filter(
|
|
6424
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6425
|
+
).slice(0, 6) : [];
|
|
6426
|
+
const relationshipKeys = Array.isArray(lastInputEdit.changedRelationshipKeys) ? lastInputEdit.changedRelationshipKeys.filter(
|
|
6427
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6428
|
+
).slice(0, 6) : [];
|
|
6429
|
+
const changed = [
|
|
6430
|
+
inputKeys.length ? `inputs=${inputKeys.join(",")}` : null,
|
|
6431
|
+
relationshipKeys.length ? `relationships=${relationshipKeys.join(",")}` : null
|
|
6432
|
+
].filter(Boolean);
|
|
6433
|
+
return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
|
|
6434
|
+
}
|
|
6435
|
+
function artifactIssueSummary(record) {
|
|
6436
|
+
const validation = asRecord3(record.validation);
|
|
6437
|
+
if (!validation) return null;
|
|
6438
|
+
const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
|
|
6439
|
+
if (issues.length > 0) {
|
|
6440
|
+
return `issues=${issues.map((issue) => {
|
|
6441
|
+
const code = asString(issue.code) || asString(issue.kind) || "issue";
|
|
6442
|
+
const path = asString(issue.path);
|
|
6443
|
+
const message = trimString(issue.message);
|
|
6444
|
+
return `${code}${path ? ` at ${path}` : ""}${message ? ` (${message})` : ""}`;
|
|
6445
|
+
}).join("; ")}`;
|
|
6446
|
+
}
|
|
6447
|
+
const error = trimString(validation.error) || trimString(validation.reason) || trimString(validation.message);
|
|
6448
|
+
return error ? `validation=${error}` : null;
|
|
6449
|
+
}
|
|
6450
|
+
function artifactExecutionSummary(metadata) {
|
|
6451
|
+
const execution = asRecord3(metadata.execution);
|
|
6452
|
+
if (!execution) return null;
|
|
6453
|
+
const result = asRecord3(execution.result);
|
|
6454
|
+
const awaiting = asString(result?.awaiting) || asString(execution.awaiting);
|
|
6455
|
+
const pendingTransition = asString(result?.pendingTransition) || asString(execution.pendingTransition);
|
|
6456
|
+
const approval = asRecord3(result?.approval) || asRecord3(execution.approval);
|
|
6457
|
+
const approvalTarget = asString(approval?.permissionProfileName) || asString(approval?.permissionProfileId) || asString(approval?.assigneeSubjectId);
|
|
6458
|
+
const error = trimString(execution.error);
|
|
6459
|
+
const pieces = [
|
|
6460
|
+
awaiting ? `awaiting=${awaiting}` : null,
|
|
6461
|
+
pendingTransition ? `pendingTransition=${pendingTransition}` : null,
|
|
6462
|
+
approvalTarget ? `approvalTarget=${approvalTarget}` : null,
|
|
6463
|
+
error ? `executionError=${error}` : null
|
|
6464
|
+
].filter(Boolean);
|
|
6465
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6466
|
+
}
|
|
6467
|
+
function artifactStatePathSummary(metadata) {
|
|
6468
|
+
const statePlan = asRecord3(metadata.statePlan);
|
|
6469
|
+
if (!statePlan) return null;
|
|
6470
|
+
const machineName = asString(statePlan.machineName);
|
|
6471
|
+
const targetState = asString(statePlan.targetState);
|
|
6472
|
+
const objectPath = asString(statePlan.objectPath);
|
|
6473
|
+
const approvedTransitions = Array.isArray(statePlan.approvedTransitions) ? statePlan.approvedTransitions.length : 0;
|
|
6474
|
+
const approvalDecisions = Array.isArray(statePlan.approvalDecisions) ? statePlan.approvalDecisions.length : 0;
|
|
6475
|
+
const pieces = [
|
|
6476
|
+
machineName || targetState ? `statePath=${machineName || "state_machine"}${targetState ? ` -> ${targetState}` : ""}` : null,
|
|
6477
|
+
objectPath ? `objectPath=${objectPath}` : null,
|
|
6478
|
+
approvedTransitions ? `approvedTransitions=${approvedTransitions}` : null,
|
|
6479
|
+
approvalDecisions ? `approvalDecisions=${approvalDecisions}` : null
|
|
6480
|
+
].filter(Boolean);
|
|
6481
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6482
|
+
}
|
|
6483
|
+
function artifactSummaryLine(artifactId, record) {
|
|
6484
|
+
if (!record) return `- ${artifactId}: unavailable in session artifact store`;
|
|
6485
|
+
const label = trimString(record.label) || artifactId;
|
|
6486
|
+
const kind = asString(record.kind) || "artifact";
|
|
6487
|
+
const status = asString(record.status) || "unknown";
|
|
6488
|
+
const createdByJobId = asString(record.createdByJobId);
|
|
6489
|
+
const target = asRecord3(record.target);
|
|
6490
|
+
const metadata = asRecord3(record.metadata) || {};
|
|
6491
|
+
const subArtifactIds = Array.isArray(record.subArtifactIds) ? record.subArtifactIds.filter(
|
|
6492
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
6493
|
+
).slice(0, 8) : [];
|
|
6494
|
+
const relationships = compactJson(record.relationships, 220);
|
|
6495
|
+
const pieces = [
|
|
6496
|
+
`kind=${kind}`,
|
|
6497
|
+
`status=${status}`,
|
|
6498
|
+
createdByJobId ? `createdByJob=${createdByJobId}` : null,
|
|
6499
|
+
target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
|
|
6500
|
+
artifactStatePathSummary(metadata),
|
|
6501
|
+
artifactExecutionSummary(metadata),
|
|
6502
|
+
artifactIssueSummary(record),
|
|
6503
|
+
latestInputEditSummary(metadata),
|
|
6504
|
+
subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
|
|
6505
|
+
relationships ? `relationships=${relationships}` : null
|
|
6506
|
+
].filter(Boolean);
|
|
6507
|
+
return `- ${artifactId}: ${label}${pieces.length ? `; ${pieces.join("; ")}` : ""}`;
|
|
6508
|
+
}
|
|
6509
|
+
function buildArtifactHistory(show, artifactsById) {
|
|
6371
6510
|
if (!show) return void 0;
|
|
6372
|
-
|
|
6511
|
+
const artifactIds = show.sessionArtifactIds || [];
|
|
6512
|
+
const actionSuggestions = show.actionSuggestions || [];
|
|
6513
|
+
if (artifactIds.length === 0 && actionSuggestions.length === 0) {
|
|
6514
|
+
return `[Agent message]
|
|
6373
6515
|
${stringifyTranscriptValue({ show }, "")}`;
|
|
6516
|
+
}
|
|
6517
|
+
const lines = artifactIds.slice(0, 8).map(
|
|
6518
|
+
(artifactId) => artifactSummaryLine(artifactId, artifactsById?.[artifactId])
|
|
6519
|
+
);
|
|
6520
|
+
if (artifactIds.length > 8) {
|
|
6521
|
+
lines.push(`- ${artifactIds.length - 8} more artifacts omitted`);
|
|
6522
|
+
}
|
|
6523
|
+
if (actionSuggestions.length > 0) {
|
|
6524
|
+
if (artifactIds.length > 0) lines.push("[Agent suggested actions]");
|
|
6525
|
+
for (const suggestion of actionSuggestions.slice(0, 8)) {
|
|
6526
|
+
lines.push(
|
|
6527
|
+
`- ${suggestion.label}${suggestion.description ? `; ${suggestion.description}` : ""}`
|
|
6528
|
+
);
|
|
6529
|
+
}
|
|
6530
|
+
if (actionSuggestions.length > 8) {
|
|
6531
|
+
lines.push(`- ${actionSuggestions.length - 8} more suggestions omitted`);
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
const otherRefs = {
|
|
6535
|
+
entryPaths: show.entryPaths,
|
|
6536
|
+
listNames: show.listNames,
|
|
6537
|
+
variableNames: show.variableNames,
|
|
6538
|
+
fileIds: show.fileIds
|
|
6539
|
+
};
|
|
6540
|
+
const hasOtherRefs = Object.values(otherRefs).some(
|
|
6541
|
+
(value) => Array.isArray(value) && value.length > 0
|
|
6542
|
+
);
|
|
6543
|
+
const title = artifactIds.length > 0 ? "[Agent displayed session artifacts]" : "[Agent suggested actions]";
|
|
6544
|
+
return [
|
|
6545
|
+
title,
|
|
6546
|
+
...lines,
|
|
6547
|
+
hasOtherRefs ? `Other shown refs: ${stringifyTranscriptValue(otherRefs, "")}` : null
|
|
6548
|
+
].filter(Boolean).join("\n");
|
|
6374
6549
|
}
|
|
6375
|
-
function normalizeConversationMessage(raw) {
|
|
6550
|
+
function normalizeConversationMessage(raw, artifactsById) {
|
|
6376
6551
|
const record = asRecord3(raw);
|
|
6377
6552
|
if (!record) return null;
|
|
6378
6553
|
const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
|
|
@@ -6384,6 +6559,12 @@ function normalizeConversationMessage(raw) {
|
|
|
6384
6559
|
const id = asString(record.id) || crypto.randomUUID();
|
|
6385
6560
|
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
6386
6561
|
if (!content && !show) return null;
|
|
6562
|
+
const artifactHistory = buildArtifactHistory(show, artifactsById);
|
|
6563
|
+
const historyContent = role === "assistant" ? content && artifactHistory ? `[Assistant reply]
|
|
6564
|
+
${content}
|
|
6565
|
+
|
|
6566
|
+
${artifactHistory}` : content ? `[Assistant reply]
|
|
6567
|
+
${content}` : artifactHistory : void 0;
|
|
6387
6568
|
return {
|
|
6388
6569
|
id,
|
|
6389
6570
|
role,
|
|
@@ -6392,8 +6573,7 @@ function normalizeConversationMessage(raw) {
|
|
|
6392
6573
|
jobId: asString(record.jobId),
|
|
6393
6574
|
promptId: asString(record.promptId),
|
|
6394
6575
|
show,
|
|
6395
|
-
historyContent
|
|
6396
|
-
${content}` : buildArtifactHistory(show) : void 0,
|
|
6576
|
+
historyContent,
|
|
6397
6577
|
source: "conversation"
|
|
6398
6578
|
};
|
|
6399
6579
|
}
|
|
@@ -6436,7 +6616,7 @@ ${assistantContent}`,
|
|
|
6436
6616
|
return entries;
|
|
6437
6617
|
});
|
|
6438
6618
|
}
|
|
6439
|
-
function normalizeAgentMessageEntries(jobId, rawMessages) {
|
|
6619
|
+
function normalizeAgentMessageEntries(jobId, rawMessages, artifactsById) {
|
|
6440
6620
|
return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
6441
6621
|
(left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
|
|
6442
6622
|
).flatMap((message) => {
|
|
@@ -6467,14 +6647,14 @@ ${reply}`,
|
|
|
6467
6647
|
timestamp,
|
|
6468
6648
|
jobId,
|
|
6469
6649
|
show,
|
|
6470
|
-
historyContent: buildArtifactHistory(show),
|
|
6650
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6471
6651
|
source: "job_agent_message"
|
|
6472
6652
|
});
|
|
6473
6653
|
}
|
|
6474
6654
|
return entries;
|
|
6475
6655
|
});
|
|
6476
6656
|
}
|
|
6477
|
-
function buildJobFallbackEntries(jobId, job, sessionHeap) {
|
|
6657
|
+
function buildJobFallbackEntries(jobId, job, sessionHeap, artifactsById) {
|
|
6478
6658
|
const timestamp = asNumber(job.finishedAt) || asNumber(job.startedAt) || asNumber(job.submittedAt) || 0;
|
|
6479
6659
|
const resultPreview = stringifyTranscriptValue(
|
|
6480
6660
|
job.result,
|
|
@@ -6512,7 +6692,7 @@ ${responseText}`,
|
|
|
6512
6692
|
timestamp,
|
|
6513
6693
|
jobId,
|
|
6514
6694
|
show,
|
|
6515
|
-
historyContent: buildArtifactHistory(show),
|
|
6695
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6516
6696
|
source: "job_result"
|
|
6517
6697
|
});
|
|
6518
6698
|
}
|
|
@@ -6566,10 +6746,11 @@ function buildJobCodeEntry(jobId, job) {
|
|
|
6566
6746
|
function buildSessionTranscript(input) {
|
|
6567
6747
|
const liveDoc = input.liveDoc || null;
|
|
6568
6748
|
const sessionHeap = input.sessionHeap || EMPTY_HEAP;
|
|
6749
|
+
const artifactsById = artifactRecordsById(liveDoc);
|
|
6569
6750
|
const transcript = [];
|
|
6570
6751
|
const conversationMessages = asArray(
|
|
6571
6752
|
asRecord3(liveDoc?.conversation)?.messages
|
|
6572
|
-
).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
|
|
6753
|
+
).map((message) => normalizeConversationMessage(message, artifactsById)).filter((message) => Boolean(message));
|
|
6573
6754
|
const conversationPromptIds = new Set(
|
|
6574
6755
|
conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
|
|
6575
6756
|
);
|
|
@@ -6596,7 +6777,8 @@ function buildSessionTranscript(input) {
|
|
|
6596
6777
|
if (!assistantConversationJobIds.has(jobId)) {
|
|
6597
6778
|
const agentEntries = normalizeAgentMessageEntries(
|
|
6598
6779
|
jobId,
|
|
6599
|
-
job.agentMessages
|
|
6780
|
+
job.agentMessages,
|
|
6781
|
+
artifactsById
|
|
6600
6782
|
);
|
|
6601
6783
|
if (agentEntries.length > 0) {
|
|
6602
6784
|
transcript.push(...agentEntries);
|
|
@@ -6605,7 +6787,8 @@ function buildSessionTranscript(input) {
|
|
|
6605
6787
|
...buildJobFallbackEntries(
|
|
6606
6788
|
jobId,
|
|
6607
6789
|
job,
|
|
6608
|
-
sessionHeap
|
|
6790
|
+
sessionHeap,
|
|
6791
|
+
artifactsById
|
|
6609
6792
|
)
|
|
6610
6793
|
);
|
|
6611
6794
|
}
|
|
@@ -10771,16 +10954,107 @@ var StateMachineStateSchema = external_exports.union([
|
|
|
10771
10954
|
external_exports.string(),
|
|
10772
10955
|
external_exports.object({
|
|
10773
10956
|
name: external_exports.string().min(1),
|
|
10957
|
+
label: external_exports.string().optional(),
|
|
10958
|
+
description: external_exports.string().optional(),
|
|
10774
10959
|
isFinal: external_exports.boolean().optional()
|
|
10775
10960
|
}).strict()
|
|
10776
10961
|
]);
|
|
10962
|
+
var StateTransitionInputBindingSchema = external_exports.lazy(
|
|
10963
|
+
() => external_exports.union([
|
|
10964
|
+
external_exports.null(),
|
|
10965
|
+
external_exports.string(),
|
|
10966
|
+
external_exports.number(),
|
|
10967
|
+
external_exports.boolean(),
|
|
10968
|
+
external_exports.array(StateTransitionInputBindingSchema),
|
|
10969
|
+
external_exports.object({
|
|
10970
|
+
const: external_exports.unknown()
|
|
10971
|
+
}).strict(),
|
|
10972
|
+
external_exports.object({
|
|
10973
|
+
from: external_exports.literal("object"),
|
|
10974
|
+
path: external_exports.string().min(1),
|
|
10975
|
+
editable: external_exports.boolean().optional()
|
|
10976
|
+
}).strict(),
|
|
10977
|
+
external_exports.object({
|
|
10978
|
+
from: external_exports.literal("field"),
|
|
10979
|
+
name: external_exports.string().min(1),
|
|
10980
|
+
editable: external_exports.boolean().optional()
|
|
10981
|
+
}).strict(),
|
|
10982
|
+
external_exports.object({
|
|
10983
|
+
from: external_exports.literal("relationship"),
|
|
10984
|
+
name: external_exports.string().min(1),
|
|
10985
|
+
path: external_exports.string().min(1).optional(),
|
|
10986
|
+
many: external_exports.boolean().optional(),
|
|
10987
|
+
editable: external_exports.boolean().optional()
|
|
10988
|
+
}).strict(),
|
|
10989
|
+
external_exports.object({
|
|
10990
|
+
from: external_exports.literal("session"),
|
|
10991
|
+
path: external_exports.string().min(1),
|
|
10992
|
+
editable: external_exports.boolean().optional()
|
|
10993
|
+
}).strict(),
|
|
10994
|
+
external_exports.object({
|
|
10995
|
+
from: external_exports.literal("actor"),
|
|
10996
|
+
path: external_exports.string().min(1),
|
|
10997
|
+
editable: external_exports.boolean().optional()
|
|
10998
|
+
}).strict(),
|
|
10999
|
+
external_exports.record(external_exports.string(), StateTransitionInputBindingSchema)
|
|
11000
|
+
])
|
|
11001
|
+
);
|
|
11002
|
+
var StateTransitionActionSchema = external_exports.object({
|
|
11003
|
+
effect: external_exports.string().min(1),
|
|
11004
|
+
input: external_exports.record(external_exports.string(), StateTransitionInputBindingSchema).optional()
|
|
11005
|
+
}).strict();
|
|
11006
|
+
var StateTransitionAssigneeSchema = external_exports.object({
|
|
11007
|
+
kind: external_exports.string().min(1),
|
|
11008
|
+
from: StateTransitionInputBindingSchema.optional(),
|
|
11009
|
+
role: external_exports.string().optional(),
|
|
11010
|
+
label: external_exports.string().optional()
|
|
11011
|
+
}).strict();
|
|
11012
|
+
var StateTransitionRelatedStateRequirementSchema = external_exports.object({
|
|
11013
|
+
relationship: external_exports.string().min(1),
|
|
11014
|
+
machine: external_exports.string().min(1),
|
|
11015
|
+
state: external_exports.string().min(1),
|
|
11016
|
+
className: external_exports.string().min(1).optional(),
|
|
11017
|
+
label: external_exports.string().optional(),
|
|
11018
|
+
mode: external_exports.enum(["every", "some", "any"]).optional()
|
|
11019
|
+
}).strict();
|
|
11020
|
+
var StateTransitionRequirementsSchema = external_exports.object({
|
|
11021
|
+
fields: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11022
|
+
relationships: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11023
|
+
relatedStates: external_exports.array(StateTransitionRelatedStateRequirementSchema).optional()
|
|
11024
|
+
}).strict();
|
|
11025
|
+
var StateTransitionPermissionSchema = external_exports.union([
|
|
11026
|
+
external_exports.string().min(1),
|
|
11027
|
+
external_exports.object({
|
|
11028
|
+
profile: external_exports.string().min(1).optional(),
|
|
11029
|
+
profileId: external_exports.string().min(1).optional(),
|
|
11030
|
+
label: external_exports.string().optional(),
|
|
11031
|
+
reason: external_exports.string().optional()
|
|
11032
|
+
}).strict()
|
|
11033
|
+
]);
|
|
11034
|
+
var StateTransitionExpectedOutcomeSchema = external_exports.union([
|
|
11035
|
+
external_exports.string().min(1),
|
|
11036
|
+
external_exports.object({
|
|
11037
|
+
machine: external_exports.string().min(1).optional(),
|
|
11038
|
+
state: external_exports.string().min(1),
|
|
11039
|
+
summary: external_exports.string().optional()
|
|
11040
|
+
}).strict()
|
|
11041
|
+
]);
|
|
10777
11042
|
var StateMachineTransitionSchema = external_exports.object({
|
|
10778
11043
|
name: external_exports.string().min(1),
|
|
10779
11044
|
from: external_exports.string().min(1),
|
|
10780
|
-
to: external_exports.string().min(1)
|
|
11045
|
+
to: external_exports.string().min(1),
|
|
11046
|
+
label: external_exports.string().optional(),
|
|
11047
|
+
description: external_exports.string().optional(),
|
|
11048
|
+
action: StateTransitionActionSchema.optional(),
|
|
11049
|
+
assignee: StateTransitionAssigneeSchema.optional(),
|
|
11050
|
+
requirements: StateTransitionRequirementsSchema.optional(),
|
|
11051
|
+
permission: StateTransitionPermissionSchema.optional(),
|
|
11052
|
+
risk: external_exports.enum(["low", "medium", "high"]).optional(),
|
|
11053
|
+
expectedOutcome: StateTransitionExpectedOutcomeSchema.optional()
|
|
10781
11054
|
}).strict();
|
|
10782
11055
|
external_exports.object({
|
|
10783
11056
|
name: external_exports.string().min(1),
|
|
11057
|
+
stateField: external_exports.string().min(1).optional(),
|
|
10784
11058
|
entryState: external_exports.string().min(1),
|
|
10785
11059
|
states: external_exports.array(StateMachineStateSchema).min(1),
|
|
10786
11060
|
transitions: external_exports.array(StateMachineTransitionSchema),
|
|
@@ -10847,6 +11121,16 @@ var PoliciesSchema = external_exports.object({
|
|
|
10847
11121
|
confirmWhen: external_exports.array(PolicyRuleSchema).optional(),
|
|
10848
11122
|
denyWhen: external_exports.array(PolicyRuleSchema).optional()
|
|
10849
11123
|
}).strict();
|
|
11124
|
+
var CreatesSchema = external_exports.union([
|
|
11125
|
+
external_exports.string().min(1),
|
|
11126
|
+
external_exports.object({
|
|
11127
|
+
className: external_exports.string().min(1),
|
|
11128
|
+
idPath: external_exports.string().min(1).optional(),
|
|
11129
|
+
pathPath: external_exports.string().min(1).optional(),
|
|
11130
|
+
statePath: external_exports.string().min(1).optional(),
|
|
11131
|
+
classStateHandle: external_exports.boolean().optional()
|
|
11132
|
+
}).strict()
|
|
11133
|
+
]);
|
|
10850
11134
|
external_exports.object({
|
|
10851
11135
|
postCondition: external_exports.union([
|
|
10852
11136
|
external_exports.string(),
|
|
@@ -10877,6 +11161,7 @@ external_exports.object({
|
|
|
10877
11161
|
mode: external_exports.string().optional()
|
|
10878
11162
|
}).strict()
|
|
10879
11163
|
]).optional(),
|
|
11164
|
+
creates: CreatesSchema.optional(),
|
|
10880
11165
|
access: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10881
11166
|
effectKind: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10882
11167
|
sideEffect: external_exports.enum(["read", "write", "ui", "readonly", "read_only"]).optional(),
|
|
@@ -11104,9 +11389,10 @@ function mergeMethodSummaryPatch(target, patch) {
|
|
|
11104
11389
|
if (patch.metamodels !== void 0) target.metamodels = patch.metamodels;
|
|
11105
11390
|
if (patch.effectBehaviors !== void 0)
|
|
11106
11391
|
target.effectBehaviors = patch.effectBehaviors;
|
|
11392
|
+
if (patch.creates !== void 0) target.creates = patch.creates;
|
|
11107
11393
|
if (patch.static !== void 0) target.static = patch.static;
|
|
11108
11394
|
}
|
|
11109
|
-
function
|
|
11395
|
+
function toPascalCase2(value) {
|
|
11110
11396
|
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
11111
11397
|
}
|
|
11112
11398
|
function normalizeNotesInput(input) {
|
|
@@ -11164,29 +11450,60 @@ function normalizeEffectBehaviorSummary(metamodels) {
|
|
|
11164
11450
|
}
|
|
11165
11451
|
return Object.keys(result).length > 0 ? result : null;
|
|
11166
11452
|
}
|
|
11167
|
-
function
|
|
11168
|
-
if (!
|
|
11169
|
-
|
|
11453
|
+
function normalizeCreationSummary(metamodels) {
|
|
11454
|
+
if (!isObject(metamodels)) return null;
|
|
11455
|
+
let raw = metamodels.creates;
|
|
11456
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11457
|
+
const trimmed = raw.trim();
|
|
11458
|
+
if (trimmed.startsWith("{") || trimmed.startsWith('"')) {
|
|
11459
|
+
try {
|
|
11460
|
+
raw = JSON.parse(trimmed);
|
|
11461
|
+
} catch {
|
|
11462
|
+
return { className: trimmed };
|
|
11463
|
+
}
|
|
11464
|
+
} else {
|
|
11465
|
+
return { className: trimmed };
|
|
11466
|
+
}
|
|
11170
11467
|
}
|
|
11468
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11469
|
+
return { className: raw.trim() };
|
|
11470
|
+
}
|
|
11471
|
+
if (!isObject(raw)) return null;
|
|
11472
|
+
const className = typeof raw.className === "string" && raw.className.trim() ? raw.className.trim() : "";
|
|
11473
|
+
if (!className) return null;
|
|
11474
|
+
return {
|
|
11475
|
+
className,
|
|
11476
|
+
...typeof raw.idPath === "string" && raw.idPath.trim() ? { idPath: raw.idPath.trim() } : {},
|
|
11477
|
+
...typeof raw.pathPath === "string" && raw.pathPath.trim() ? { pathPath: raw.pathPath.trim() } : {},
|
|
11478
|
+
...typeof raw.statePath === "string" && raw.statePath.trim() ? { statePath: raw.statePath.trim() } : {},
|
|
11479
|
+
...typeof raw.classStateHandle === "boolean" ? { classStateHandle: raw.classStateHandle } : {}
|
|
11480
|
+
};
|
|
11481
|
+
}
|
|
11482
|
+
function buildEffectBehaviorDocs(effectBehaviors, creates) {
|
|
11171
11483
|
const docs = [];
|
|
11172
|
-
if (
|
|
11484
|
+
if (creates) {
|
|
11485
|
+
docs.push(
|
|
11486
|
+
`Creation method: creates ${creates.className}. The agent may use generated class-level new-record action methods for this class.`
|
|
11487
|
+
);
|
|
11488
|
+
}
|
|
11489
|
+
if (effectBehaviors?.approvalRequired?.required) {
|
|
11173
11490
|
docs.push(
|
|
11174
11491
|
effectBehaviors.approvalRequired.reason ? `Approval required: ${effectBehaviors.approvalRequired.reason}.` : "Approval required before execution."
|
|
11175
11492
|
);
|
|
11176
11493
|
}
|
|
11177
|
-
if (effectBehaviors
|
|
11494
|
+
if (effectBehaviors?.postCondition) {
|
|
11178
11495
|
docs.push(`Post-condition: ${effectBehaviors.postCondition.condition}.`);
|
|
11179
11496
|
if (effectBehaviors.postCondition.description) {
|
|
11180
11497
|
docs.push(effectBehaviors.postCondition.description);
|
|
11181
11498
|
}
|
|
11182
11499
|
}
|
|
11183
|
-
if (effectBehaviors
|
|
11500
|
+
if (effectBehaviors?.dryRun?.enabled) {
|
|
11184
11501
|
docs.push("Supports dry run.");
|
|
11185
11502
|
if (effectBehaviors.dryRun.description) {
|
|
11186
11503
|
docs.push(effectBehaviors.dryRun.description);
|
|
11187
11504
|
}
|
|
11188
11505
|
}
|
|
11189
|
-
if (effectBehaviors
|
|
11506
|
+
if (effectBehaviors?.reverse) {
|
|
11190
11507
|
if (effectBehaviors.reverse.handler) {
|
|
11191
11508
|
docs.push(`Reverse handler: ${effectBehaviors.reverse.handler}.`);
|
|
11192
11509
|
} else {
|
|
@@ -11245,13 +11562,21 @@ function buildEffectBehaviorMutations(toolPath, spec) {
|
|
|
11245
11562
|
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { set_approval_required(${args}) { kind } } }`
|
|
11246
11563
|
});
|
|
11247
11564
|
}
|
|
11565
|
+
if (spec.creates !== void 0) {
|
|
11566
|
+
mutations.push({
|
|
11567
|
+
label: `set creates on ${toolPath}`,
|
|
11568
|
+
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "creates", label: "creates") { set_string_value(value: ${JSON.stringify(
|
|
11569
|
+
JSON.stringify(spec.creates)
|
|
11570
|
+
)}) { done } } } }`
|
|
11571
|
+
});
|
|
11572
|
+
}
|
|
11248
11573
|
return mutations;
|
|
11249
11574
|
}
|
|
11250
11575
|
function readMethodEffectBehaviors(rawMethod) {
|
|
11576
|
+
const metamodels = isObject(rawMethod.metamodels) ? rawMethod.metamodels : null;
|
|
11251
11577
|
return {
|
|
11252
|
-
effectBehaviors: normalizeEffectBehaviorSummary(
|
|
11253
|
-
|
|
11254
|
-
)
|
|
11578
|
+
effectBehaviors: normalizeEffectBehaviorSummary(metamodels),
|
|
11579
|
+
creates: normalizeCreationSummary(metamodels)
|
|
11255
11580
|
};
|
|
11256
11581
|
}
|
|
11257
11582
|
var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
@@ -11273,6 +11598,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11273
11598
|
{
|
|
11274
11599
|
key: "approvalRequired",
|
|
11275
11600
|
description: "Boolean or `{ required, reason, mode }`."
|
|
11601
|
+
},
|
|
11602
|
+
{
|
|
11603
|
+
key: "creates",
|
|
11604
|
+
description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, classStateHandle }`.'
|
|
11276
11605
|
}
|
|
11277
11606
|
]
|
|
11278
11607
|
},
|
|
@@ -11392,7 +11721,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11392
11721
|
...methodIR,
|
|
11393
11722
|
docs: [
|
|
11394
11723
|
...methodIR.docs,
|
|
11395
|
-
...buildEffectBehaviorDocs(
|
|
11724
|
+
...buildEffectBehaviorDocs(
|
|
11725
|
+
methodSummary.effectBehaviors,
|
|
11726
|
+
methodSummary.creates
|
|
11727
|
+
)
|
|
11396
11728
|
]
|
|
11397
11729
|
};
|
|
11398
11730
|
}
|
|
@@ -11633,15 +11965,50 @@ function toRecordSearchResult(className, node) {
|
|
|
11633
11965
|
return [];
|
|
11634
11966
|
}
|
|
11635
11967
|
) : [];
|
|
11968
|
+
const graphPathId = extractRecordIdFromGraphPath(path, className);
|
|
11969
|
+
const realIdField = fields.find(
|
|
11970
|
+
(field) => normalizeGraphPathSegment(field.name) === "real_id" && typeof field.value === "string" && field.value.trim()
|
|
11971
|
+
);
|
|
11972
|
+
const id = typeof realIdField?.value === "string" ? realIdField.value.trim() : graphPathId;
|
|
11973
|
+
const rawLabel = typeof node.label === "string" && node.label.trim() ? node.label : "";
|
|
11974
|
+
if (fields.length === 0 && rawLabel && isPlaceholderRecordLabel(rawLabel, graphPathId, path)) {
|
|
11975
|
+
return null;
|
|
11976
|
+
}
|
|
11977
|
+
const fallbackLabel = displayLabelFromFields(fields);
|
|
11978
|
+
const label = rawLabel && !isPlaceholderRecordLabel(rawLabel, id, path) ? rawLabel : fallbackLabel || rawLabel || id;
|
|
11636
11979
|
return {
|
|
11637
11980
|
path,
|
|
11638
11981
|
className,
|
|
11639
|
-
id
|
|
11640
|
-
label
|
|
11982
|
+
id,
|
|
11983
|
+
label,
|
|
11641
11984
|
description: typeof node.description === "string" && node.description.trim() ? node.description : null,
|
|
11642
11985
|
fields
|
|
11643
11986
|
};
|
|
11644
11987
|
}
|
|
11988
|
+
function isPlaceholderRecordLabel(label, id, path) {
|
|
11989
|
+
const normalizedLabel = normalizeGraphPathSegment(label);
|
|
11990
|
+
return normalizedLabel === normalizeGraphPathSegment(id) || normalizedLabel === normalizeGraphPathSegment(path);
|
|
11991
|
+
}
|
|
11992
|
+
function displayLabelFromFields(fields) {
|
|
11993
|
+
const preferredFieldNames = [
|
|
11994
|
+
"name",
|
|
11995
|
+
"title",
|
|
11996
|
+
"label",
|
|
11997
|
+
"display_name",
|
|
11998
|
+
"file_name",
|
|
11999
|
+
"number",
|
|
12000
|
+
"code"
|
|
12001
|
+
];
|
|
12002
|
+
for (const preferred of preferredFieldNames) {
|
|
12003
|
+
const match = fields.find(
|
|
12004
|
+
(field) => normalizeGraphPathSegment(field.name) === preferred && typeof field.value === "string" && field.value.trim()
|
|
12005
|
+
);
|
|
12006
|
+
if (typeof match?.value === "string") {
|
|
12007
|
+
return match.value.trim();
|
|
12008
|
+
}
|
|
12009
|
+
}
|
|
12010
|
+
return null;
|
|
12011
|
+
}
|
|
11645
12012
|
function normalizeRecordSearchText(value) {
|
|
11646
12013
|
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
|
|
11647
12014
|
}
|
|
@@ -12541,15 +12908,47 @@ var searchableMetamodelPackage = defineMetamodelPackage({
|
|
|
12541
12908
|
|
|
12542
12909
|
// ../metamodel-state-machine/src/index.ts
|
|
12543
12910
|
function normalizeStateMachines(values) {
|
|
12911
|
+
const parseJsonRecord = (value) => {
|
|
12912
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
12913
|
+
return value;
|
|
12914
|
+
}
|
|
12915
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
12916
|
+
try {
|
|
12917
|
+
const parsed = JSON.parse(value);
|
|
12918
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
12919
|
+
} catch {
|
|
12920
|
+
return null;
|
|
12921
|
+
}
|
|
12922
|
+
};
|
|
12923
|
+
const parseJsonValue = (value) => {
|
|
12924
|
+
if (value === null || typeof value === "undefined") return null;
|
|
12925
|
+
if (typeof value !== "string") return value;
|
|
12926
|
+
if (!value.trim()) return null;
|
|
12927
|
+
try {
|
|
12928
|
+
return JSON.parse(value);
|
|
12929
|
+
} catch {
|
|
12930
|
+
return value;
|
|
12931
|
+
}
|
|
12932
|
+
};
|
|
12544
12933
|
return (values || []).map((machine) => {
|
|
12545
12934
|
const states = (machine?.states || []).map((state) => ({
|
|
12546
12935
|
name: String(state?.name || ""),
|
|
12547
|
-
|
|
12936
|
+
label: typeof state?.label === "string" ? state.label : null,
|
|
12937
|
+
description: typeof state?.description === "string" ? state.description : null,
|
|
12938
|
+
isFinal: Boolean(state?.is_final ?? state?.isFinal)
|
|
12548
12939
|
})).filter((state) => state.name.length > 0);
|
|
12549
12940
|
const transitions = (machine?.transitions || []).map((transition) => ({
|
|
12550
12941
|
name: String(transition?.name || ""),
|
|
12551
12942
|
from: String(transition?.from?.name || ""),
|
|
12552
|
-
to: String(transition?.to?.name || "")
|
|
12943
|
+
to: String(transition?.to?.name || ""),
|
|
12944
|
+
label: typeof transition?.label === "string" ? transition.label : null,
|
|
12945
|
+
description: typeof transition?.description === "string" ? transition.description : null,
|
|
12946
|
+
action: parseJsonRecord(transition?.action) || parseJsonRecord(transition?.action_json),
|
|
12947
|
+
assignee: parseJsonRecord(transition?.assignee) || parseJsonRecord(transition?.assignee_json),
|
|
12948
|
+
requirements: parseJsonRecord(transition?.requirements) || parseJsonRecord(transition?.requirements_json),
|
|
12949
|
+
permission: parseJsonValue(transition?.permission) ?? parseJsonValue(transition?.permission_json),
|
|
12950
|
+
risk: transition?.risk === "low" || transition?.risk === "medium" || transition?.risk === "high" ? transition.risk : null,
|
|
12951
|
+
expectedOutcome: parseJsonValue(transition?.expectedOutcome) ?? parseJsonValue(transition?.expected_outcome_json)
|
|
12553
12952
|
})).filter(
|
|
12554
12953
|
(transition) => transition.name.length > 0 && transition.from.length > 0 && transition.to.length > 0
|
|
12555
12954
|
);
|
|
@@ -12563,7 +12962,7 @@ function normalizeStateMachines(values) {
|
|
|
12563
12962
|
}).filter((machine) => machine.name.length > 0);
|
|
12564
12963
|
}
|
|
12565
12964
|
function stateTypeName(className, machineName) {
|
|
12566
|
-
return `${
|
|
12965
|
+
return `${toPascalCase2(className)}${toPascalCase2(machineName)}`;
|
|
12567
12966
|
}
|
|
12568
12967
|
function transitionTypeName(className, machineName) {
|
|
12569
12968
|
return `${stateTypeName(className, machineName)}Transition`;
|
|
@@ -12571,6 +12970,15 @@ function transitionTypeName(className, machineName) {
|
|
|
12571
12970
|
function pathTypeName(className, machineName) {
|
|
12572
12971
|
return `${stateTypeName(className, machineName)}Path`;
|
|
12573
12972
|
}
|
|
12973
|
+
function methodToken(value) {
|
|
12974
|
+
const token = String(value || "").trim().replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
12975
|
+
return token || "state";
|
|
12976
|
+
}
|
|
12977
|
+
function transitionActionsForMachine(machine) {
|
|
12978
|
+
return Object.fromEntries(
|
|
12979
|
+
(machine.transitions || []).filter((transition) => transition.action?.effect).map((transition) => [transition.name, transition.action])
|
|
12980
|
+
);
|
|
12981
|
+
}
|
|
12574
12982
|
function normalizeStateDefinitions(machine) {
|
|
12575
12983
|
const finalStates = new Set(machine.finalStates || []);
|
|
12576
12984
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -12584,6 +12992,8 @@ function normalizeStateDefinitions(machine) {
|
|
|
12584
12992
|
}
|
|
12585
12993
|
states.set(rawState.name, {
|
|
12586
12994
|
name: rawState.name,
|
|
12995
|
+
label: rawState.label,
|
|
12996
|
+
description: rawState.description,
|
|
12587
12997
|
isFinal: Boolean(rawState.isFinal) || finalStates.has(rawState.name)
|
|
12588
12998
|
});
|
|
12589
12999
|
}
|
|
@@ -12595,6 +13005,44 @@ function normalizeStateDefinitions(machine) {
|
|
|
12595
13005
|
}
|
|
12596
13006
|
return [...states.values()];
|
|
12597
13007
|
}
|
|
13008
|
+
function transitionMetadataGraphqlArgs(transition) {
|
|
13009
|
+
const args = [];
|
|
13010
|
+
if (typeof transition.label === "string") {
|
|
13011
|
+
args.push(`label: ${JSON.stringify(transition.label)}`);
|
|
13012
|
+
}
|
|
13013
|
+
if (typeof transition.description === "string") {
|
|
13014
|
+
args.push(`description: ${JSON.stringify(transition.description)}`);
|
|
13015
|
+
}
|
|
13016
|
+
if (transition.action) {
|
|
13017
|
+
args.push(
|
|
13018
|
+
`action_json: ${JSON.stringify(JSON.stringify(transition.action))}`
|
|
13019
|
+
);
|
|
13020
|
+
}
|
|
13021
|
+
if (transition.assignee) {
|
|
13022
|
+
args.push(
|
|
13023
|
+
`assignee_json: ${JSON.stringify(JSON.stringify(transition.assignee))}`
|
|
13024
|
+
);
|
|
13025
|
+
}
|
|
13026
|
+
if (transition.requirements) {
|
|
13027
|
+
args.push(
|
|
13028
|
+
`requirements_json: ${JSON.stringify(JSON.stringify(transition.requirements))}`
|
|
13029
|
+
);
|
|
13030
|
+
}
|
|
13031
|
+
if (transition.permission) {
|
|
13032
|
+
args.push(
|
|
13033
|
+
`permission_json: ${JSON.stringify(JSON.stringify(transition.permission))}`
|
|
13034
|
+
);
|
|
13035
|
+
}
|
|
13036
|
+
if (transition.risk) {
|
|
13037
|
+
args.push(`risk: ${JSON.stringify(transition.risk)}`);
|
|
13038
|
+
}
|
|
13039
|
+
if (transition.expectedOutcome) {
|
|
13040
|
+
args.push(
|
|
13041
|
+
`expected_outcome_json: ${JSON.stringify(JSON.stringify(transition.expectedOutcome))}`
|
|
13042
|
+
);
|
|
13043
|
+
}
|
|
13044
|
+
return args.length > 0 ? `, ${args.join(", ")}` : "";
|
|
13045
|
+
}
|
|
12598
13046
|
function buildStateMachineModelMutations(modelPath, machines) {
|
|
12599
13047
|
const mutations = [];
|
|
12600
13048
|
for (const machine of machines || []) {
|
|
@@ -12605,12 +13053,13 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12605
13053
|
)}, entry_state: ${JSON.stringify(machine.entryState)}) { name } } }`
|
|
12606
13054
|
});
|
|
12607
13055
|
for (const state of normalizeStateDefinitions(machine)) {
|
|
12608
|
-
if (state.name === machine.entryState && !state.isFinal)
|
|
13056
|
+
if (state.name === machine.entryState && !state.isFinal && !state.label && !state.description)
|
|
13057
|
+
continue;
|
|
12609
13058
|
mutations.push({
|
|
12610
13059
|
label: `add state ${state.name} on ${modelPath}.${machine.name}`,
|
|
12611
13060
|
query: `mutation { at(path: ${JSON.stringify(modelPath)}) { state_machine(name: ${JSON.stringify(
|
|
12612
13061
|
machine.name
|
|
12613
|
-
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}) { name } } } }`
|
|
13062
|
+
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}, label: ${JSON.stringify(state.label || null)}, description: ${JSON.stringify(state.description || null)}) { name } } } }`
|
|
12614
13063
|
});
|
|
12615
13064
|
}
|
|
12616
13065
|
for (const transition of machine.transitions || []) {
|
|
@@ -12622,7 +13071,7 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12622
13071
|
transition.name
|
|
12623
13072
|
)}, from: ${JSON.stringify(transition.from)}, to: ${JSON.stringify(
|
|
12624
13073
|
transition.to
|
|
12625
|
-
)}) { name } } } }`
|
|
13074
|
+
)}${transitionMetadataGraphqlArgs(transition)}) { name } } } }`
|
|
12626
13075
|
});
|
|
12627
13076
|
}
|
|
12628
13077
|
}
|
|
@@ -12649,7 +13098,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12649
13098
|
const transitionName = transitionTypeName(classSummary.name, machine.name);
|
|
12650
13099
|
pathTypeName(classSummary.name, machine.name);
|
|
12651
13100
|
const docsPrefix = `${classSummary.name}.${machine.name}`;
|
|
12652
|
-
|
|
13101
|
+
const methods = [
|
|
12653
13102
|
{
|
|
12654
13103
|
name: `get_${machine.name}`,
|
|
12655
13104
|
docs: [`Get the current ${docsPrefix} state.`],
|
|
@@ -12672,7 +13121,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12672
13121
|
],
|
|
12673
13122
|
static: false,
|
|
12674
13123
|
params: [{ name: "target", type: stateName }],
|
|
12675
|
-
returnType: `Promise<${
|
|
13124
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
12676
13125
|
runtime: {
|
|
12677
13126
|
kind: "state_machine",
|
|
12678
13127
|
machineName: machine.name,
|
|
@@ -12745,6 +13194,99 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12745
13194
|
}
|
|
12746
13195
|
}
|
|
12747
13196
|
];
|
|
13197
|
+
const creationMethods = (classSummary.methods || []).filter(
|
|
13198
|
+
(method) => method.static === true && Boolean(method.creates) && method.creates?.className === classSummary.name && typeof method.effectKey === "string" && method.effectKey.length > 0
|
|
13199
|
+
);
|
|
13200
|
+
for (const state of machine.states) {
|
|
13201
|
+
const stateNameValue = typeof state === "string" ? state : String(state?.name || "");
|
|
13202
|
+
if (!stateNameValue) continue;
|
|
13203
|
+
const token = methodToken(stateNameValue);
|
|
13204
|
+
methods.push(
|
|
13205
|
+
{
|
|
13206
|
+
name: `reach_${machine.name}_to_${token}`,
|
|
13207
|
+
docs: [`Reach ${docsPrefix} state ${stateNameValue}.`],
|
|
13208
|
+
static: false,
|
|
13209
|
+
params: [],
|
|
13210
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
13211
|
+
runtime: {
|
|
13212
|
+
kind: "state_machine",
|
|
13213
|
+
machineName: machine.name,
|
|
13214
|
+
className: classSummary.name,
|
|
13215
|
+
stateTypeName: stateName,
|
|
13216
|
+
transitionTypeName: transitionName,
|
|
13217
|
+
operation: "reach",
|
|
13218
|
+
targetState: stateNameValue,
|
|
13219
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13220
|
+
}
|
|
13221
|
+
},
|
|
13222
|
+
{
|
|
13223
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13224
|
+
docs: [
|
|
13225
|
+
`Prepare a reviewable artifact that can move ${docsPrefix} to ${stateNameValue}.`
|
|
13226
|
+
],
|
|
13227
|
+
static: false,
|
|
13228
|
+
params: [],
|
|
13229
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13230
|
+
runtime: {
|
|
13231
|
+
kind: "state_machine",
|
|
13232
|
+
machineName: machine.name,
|
|
13233
|
+
className: classSummary.name,
|
|
13234
|
+
stateTypeName: stateName,
|
|
13235
|
+
transitionTypeName: transitionName,
|
|
13236
|
+
operation: "prepare_reach",
|
|
13237
|
+
targetState: stateNameValue,
|
|
13238
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13239
|
+
}
|
|
13240
|
+
}
|
|
13241
|
+
);
|
|
13242
|
+
for (const creationMethod of creationMethods) {
|
|
13243
|
+
const creationRuntime = {
|
|
13244
|
+
kind: "state_machine",
|
|
13245
|
+
machineName: machine.name,
|
|
13246
|
+
className: classSummary.name,
|
|
13247
|
+
stateTypeName: stateName,
|
|
13248
|
+
transitionTypeName: transitionName,
|
|
13249
|
+
operation: "prepare_create_reach",
|
|
13250
|
+
targetState: stateNameValue,
|
|
13251
|
+
transitionActions: transitionActionsForMachine(machine),
|
|
13252
|
+
creation: {
|
|
13253
|
+
methodName: creationMethod.name,
|
|
13254
|
+
effectKey: creationMethod.effectKey || creationMethod.name,
|
|
13255
|
+
inputSchema: creationMethod.inputSchema,
|
|
13256
|
+
outputSchema: creationMethod.outputSchema,
|
|
13257
|
+
creates: creationMethod.creates
|
|
13258
|
+
}
|
|
13259
|
+
};
|
|
13260
|
+
const viaName = `prepare_${machine.name}_to_${token}_via_${methodToken(creationMethod.name)}`;
|
|
13261
|
+
methods.push({
|
|
13262
|
+
name: viaName,
|
|
13263
|
+
docs: [
|
|
13264
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name} through ${creationMethod.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13265
|
+
],
|
|
13266
|
+
static: true,
|
|
13267
|
+
params: [
|
|
13268
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13269
|
+
],
|
|
13270
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13271
|
+
runtime: creationRuntime
|
|
13272
|
+
});
|
|
13273
|
+
if (creationMethods.length === 1) {
|
|
13274
|
+
methods.push({
|
|
13275
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13276
|
+
docs: [
|
|
13277
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13278
|
+
],
|
|
13279
|
+
static: true,
|
|
13280
|
+
params: [
|
|
13281
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13282
|
+
],
|
|
13283
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13284
|
+
runtime: creationRuntime
|
|
13285
|
+
});
|
|
13286
|
+
}
|
|
13287
|
+
}
|
|
13288
|
+
}
|
|
13289
|
+
return methods;
|
|
12748
13290
|
}
|
|
12749
13291
|
function readStateMachineSummaries(rawClass) {
|
|
12750
13292
|
return {
|
|
@@ -12767,8 +13309,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12767
13309
|
type StateMachineMutation {
|
|
12768
13310
|
name: String!
|
|
12769
13311
|
state_machine: StateMachine!
|
|
12770
|
-
add_state(name: String!, is_final: Boolean): StateMachineMutation!
|
|
12771
|
-
add_transition(name: String!, from: String!, to: String
|
|
13312
|
+
add_state(name: String!, is_final: Boolean, label: String, description: String): StateMachineMutation!
|
|
13313
|
+
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!
|
|
12772
13314
|
activate_transition(name: String!): StateMachineMutation!
|
|
12773
13315
|
}
|
|
12774
13316
|
|
|
@@ -12785,6 +13327,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12785
13327
|
type StateMachineSnapshotMutation {
|
|
12786
13328
|
snapshot: StateMachineSnapshot!
|
|
12787
13329
|
activate_transition(name: String!): StateMachineSnapshotMutation!
|
|
13330
|
+
observe_state(state: String!, force: Boolean, source: String): StateMachineSnapshotMutation!
|
|
12788
13331
|
}
|
|
12789
13332
|
|
|
12790
13333
|
type StateMachine {
|
|
@@ -12804,6 +13347,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12804
13347
|
|
|
12805
13348
|
type StateMachineState {
|
|
12806
13349
|
name: String!
|
|
13350
|
+
label: String
|
|
13351
|
+
description: String
|
|
12807
13352
|
is_final: Boolean!
|
|
12808
13353
|
}
|
|
12809
13354
|
|
|
@@ -12811,6 +13356,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12811
13356
|
name: String!
|
|
12812
13357
|
from: StateMachineState!
|
|
12813
13358
|
to: StateMachineState!
|
|
13359
|
+
label: String
|
|
13360
|
+
description: String
|
|
13361
|
+
action_json: String
|
|
13362
|
+
assignee_json: String
|
|
13363
|
+
requirements_json: String
|
|
13364
|
+
permission_json: String
|
|
13365
|
+
risk: String
|
|
13366
|
+
expected_outcome_json: String
|
|
12814
13367
|
}
|
|
12815
13368
|
|
|
12816
13369
|
type StateMachinePath {
|
|
@@ -12863,23 +13416,47 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12863
13416
|
StateMachineMutation: {
|
|
12864
13417
|
name: (value) => value.name,
|
|
12865
13418
|
state_machine: async (value) => await run(value.target.state_machine(value.name)),
|
|
12866
|
-
add_state: async (value, { name, is_final }) => {
|
|
13419
|
+
add_state: async (value, { name, is_final, label, description }) => {
|
|
12867
13420
|
await run(
|
|
12868
13421
|
value.target.add_state_machine_state(
|
|
12869
13422
|
value.name,
|
|
12870
13423
|
name,
|
|
12871
|
-
is_final ?? false
|
|
13424
|
+
is_final ?? false,
|
|
13425
|
+
label,
|
|
13426
|
+
description
|
|
12872
13427
|
)
|
|
12873
13428
|
);
|
|
12874
13429
|
return value;
|
|
12875
13430
|
},
|
|
12876
|
-
add_transition: async (value, {
|
|
13431
|
+
add_transition: async (value, {
|
|
13432
|
+
name,
|
|
13433
|
+
from,
|
|
13434
|
+
to,
|
|
13435
|
+
label,
|
|
13436
|
+
description,
|
|
13437
|
+
action_json,
|
|
13438
|
+
assignee_json,
|
|
13439
|
+
requirements_json,
|
|
13440
|
+
permission_json,
|
|
13441
|
+
risk,
|
|
13442
|
+
expected_outcome_json
|
|
13443
|
+
}) => {
|
|
12877
13444
|
await run(
|
|
12878
13445
|
value.target.add_state_machine_transition(
|
|
12879
13446
|
value.name,
|
|
12880
13447
|
name,
|
|
12881
13448
|
from,
|
|
12882
|
-
to
|
|
13449
|
+
to,
|
|
13450
|
+
{
|
|
13451
|
+
label,
|
|
13452
|
+
description,
|
|
13453
|
+
actionJson: action_json,
|
|
13454
|
+
assigneeJson: assignee_json,
|
|
13455
|
+
requirementsJson: requirements_json,
|
|
13456
|
+
permissionJson: permission_json,
|
|
13457
|
+
risk,
|
|
13458
|
+
expectedOutcomeJson: expected_outcome_json
|
|
13459
|
+
}
|
|
12883
13460
|
)
|
|
12884
13461
|
);
|
|
12885
13462
|
return value;
|
|
@@ -12898,16 +13475,37 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12898
13475
|
value.target.activate_state_machine_transition(value.name, name)
|
|
12899
13476
|
);
|
|
12900
13477
|
return value;
|
|
13478
|
+
},
|
|
13479
|
+
observe_state: async (value, { state, force, source }) => {
|
|
13480
|
+
await run(
|
|
13481
|
+
value.target.observe_state_machine_state(
|
|
13482
|
+
value.name,
|
|
13483
|
+
state,
|
|
13484
|
+
force === true,
|
|
13485
|
+
source
|
|
13486
|
+
)
|
|
13487
|
+
);
|
|
13488
|
+
return value;
|
|
12901
13489
|
}
|
|
12902
13490
|
},
|
|
12903
13491
|
StateMachineState: {
|
|
12904
13492
|
name: (value) => value.name,
|
|
13493
|
+
label: (value) => value.label || null,
|
|
13494
|
+
description: (value) => value.description || null,
|
|
12905
13495
|
is_final: (value) => value.is_final
|
|
12906
13496
|
},
|
|
12907
13497
|
StateMachineTransition: {
|
|
12908
13498
|
name: (value) => value.name,
|
|
12909
13499
|
from: (value) => value.from_state || { name: value.from, is_final: false },
|
|
12910
|
-
to: (value) => value.to_state || { name: value.to, is_final: false }
|
|
13500
|
+
to: (value) => value.to_state || { name: value.to, is_final: false },
|
|
13501
|
+
label: (value) => value.label || null,
|
|
13502
|
+
description: (value) => value.description || null,
|
|
13503
|
+
action_json: (value) => value.action_json || null,
|
|
13504
|
+
assignee_json: (value) => value.assignee_json || null,
|
|
13505
|
+
requirements_json: (value) => value.requirements_json || null,
|
|
13506
|
+
permission_json: (value) => value.permission_json || null,
|
|
13507
|
+
risk: (value) => value.risk || null,
|
|
13508
|
+
expected_outcome_json: (value) => value.expected_outcome_json || null
|
|
12911
13509
|
},
|
|
12912
13510
|
StateMachinePath: {
|
|
12913
13511
|
states: (value) => value.states,
|
|
@@ -12974,6 +13572,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12974
13572
|
name
|
|
12975
13573
|
from { name }
|
|
12976
13574
|
to { name }
|
|
13575
|
+
label
|
|
13576
|
+
description
|
|
13577
|
+
action_json
|
|
13578
|
+
assignee_json
|
|
13579
|
+
requirements_json
|
|
13580
|
+
permission_json
|
|
13581
|
+
risk
|
|
13582
|
+
expected_outcome_json
|
|
12977
13583
|
}
|
|
12978
13584
|
}`
|
|
12979
13585
|
]
|
|
@@ -13005,6 +13611,104 @@ function describeRule(rule) {
|
|
|
13005
13611
|
return `${rule.operator} ${String(rule.booleanValue)}`;
|
|
13006
13612
|
return rule.operator;
|
|
13007
13613
|
}
|
|
13614
|
+
function valueAsString(value) {
|
|
13615
|
+
if (typeof value === "string") return value;
|
|
13616
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
13617
|
+
return String(value);
|
|
13618
|
+
}
|
|
13619
|
+
return "";
|
|
13620
|
+
}
|
|
13621
|
+
function valueAsNumber(value) {
|
|
13622
|
+
if (typeof value === "number") return value;
|
|
13623
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
13624
|
+
const parsed = Number(value);
|
|
13625
|
+
return Number.isFinite(parsed) ? parsed : NaN;
|
|
13626
|
+
}
|
|
13627
|
+
return NaN;
|
|
13628
|
+
}
|
|
13629
|
+
function ruleStringValue(rule) {
|
|
13630
|
+
return rule.stringValue ?? rule.string_value ?? "";
|
|
13631
|
+
}
|
|
13632
|
+
function ruleNumberValue(rule) {
|
|
13633
|
+
return rule.numberValue ?? rule.number_value;
|
|
13634
|
+
}
|
|
13635
|
+
function ruleBooleanValue(rule) {
|
|
13636
|
+
return rule.booleanValue ?? rule.boolean_value;
|
|
13637
|
+
}
|
|
13638
|
+
function evaluateValidationRule(value, rule) {
|
|
13639
|
+
const operator = typeof rule.operator === "string" ? rule.operator : "";
|
|
13640
|
+
const stringValue2 = ruleStringValue(rule);
|
|
13641
|
+
const numberValue = ruleNumberValue(rule);
|
|
13642
|
+
const booleanValue = ruleBooleanValue(rule);
|
|
13643
|
+
let passed = true;
|
|
13644
|
+
switch (operator) {
|
|
13645
|
+
case "eq":
|
|
13646
|
+
if (numberValue !== void 0) {
|
|
13647
|
+
passed = valueAsNumber(value) === numberValue;
|
|
13648
|
+
} else if (booleanValue !== void 0) {
|
|
13649
|
+
passed = value === booleanValue;
|
|
13650
|
+
} else {
|
|
13651
|
+
passed = valueAsString(value) === stringValue2;
|
|
13652
|
+
}
|
|
13653
|
+
break;
|
|
13654
|
+
case "neq":
|
|
13655
|
+
if (numberValue !== void 0) {
|
|
13656
|
+
passed = valueAsNumber(value) !== numberValue;
|
|
13657
|
+
} else if (booleanValue !== void 0) {
|
|
13658
|
+
passed = value !== booleanValue;
|
|
13659
|
+
} else {
|
|
13660
|
+
passed = valueAsString(value) !== stringValue2;
|
|
13661
|
+
}
|
|
13662
|
+
break;
|
|
13663
|
+
case "gt":
|
|
13664
|
+
passed = valueAsNumber(value) > (numberValue ?? NaN);
|
|
13665
|
+
break;
|
|
13666
|
+
case "gte":
|
|
13667
|
+
passed = valueAsNumber(value) >= (numberValue ?? NaN);
|
|
13668
|
+
break;
|
|
13669
|
+
case "lt":
|
|
13670
|
+
passed = valueAsNumber(value) < (numberValue ?? NaN);
|
|
13671
|
+
break;
|
|
13672
|
+
case "lte":
|
|
13673
|
+
passed = valueAsNumber(value) <= (numberValue ?? NaN);
|
|
13674
|
+
break;
|
|
13675
|
+
case "true":
|
|
13676
|
+
passed = value === true;
|
|
13677
|
+
break;
|
|
13678
|
+
case "false":
|
|
13679
|
+
passed = value === false;
|
|
13680
|
+
break;
|
|
13681
|
+
case "regex":
|
|
13682
|
+
try {
|
|
13683
|
+
passed = new RegExp(stringValue2).test(valueAsString(value));
|
|
13684
|
+
} catch {
|
|
13685
|
+
passed = false;
|
|
13686
|
+
}
|
|
13687
|
+
break;
|
|
13688
|
+
case "contains":
|
|
13689
|
+
passed = valueAsString(value).includes(stringValue2);
|
|
13690
|
+
break;
|
|
13691
|
+
case "not_contains":
|
|
13692
|
+
passed = !valueAsString(value).includes(stringValue2);
|
|
13693
|
+
break;
|
|
13694
|
+
case "starts_with":
|
|
13695
|
+
passed = valueAsString(value).startsWith(stringValue2);
|
|
13696
|
+
break;
|
|
13697
|
+
case "ends_with":
|
|
13698
|
+
passed = valueAsString(value).endsWith(stringValue2);
|
|
13699
|
+
break;
|
|
13700
|
+
default:
|
|
13701
|
+
passed = true;
|
|
13702
|
+
}
|
|
13703
|
+
return {
|
|
13704
|
+
passed,
|
|
13705
|
+
operator,
|
|
13706
|
+
message: rule.message ?? null
|
|
13707
|
+
};
|
|
13708
|
+
}
|
|
13709
|
+
function validationRuleFailureMessage(path, rule) {
|
|
13710
|
+
return rule.message || `${path} failed ${rule.operator} validation`;
|
|
13711
|
+
}
|
|
13008
13712
|
function normalizeRule(rule) {
|
|
13009
13713
|
const operator = typeof rule?.operator === "string" ? rule.operator : "";
|
|
13010
13714
|
if (operator.length === 0) return null;
|
|
@@ -13227,6 +13931,26 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
13227
13931
|
var BUILTIN_MODULES = {
|
|
13228
13932
|
standard_modules: STANDARD_MODULES_OPERATIONS
|
|
13229
13933
|
};
|
|
13934
|
+
function stateNameFromMethodName(methodName) {
|
|
13935
|
+
const raw = methodName.startsWith("to") ? methodName.slice(2) : methodName;
|
|
13936
|
+
return raw.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
13937
|
+
}
|
|
13938
|
+
function appendQueryOptions(searchParams, query) {
|
|
13939
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
13940
|
+
if (value === null || typeof value === "undefined" || value === "") {
|
|
13941
|
+
continue;
|
|
13942
|
+
}
|
|
13943
|
+
if (value instanceof Date) {
|
|
13944
|
+
searchParams.set(key, value.toISOString());
|
|
13945
|
+
continue;
|
|
13946
|
+
}
|
|
13947
|
+
if (Array.isArray(value)) {
|
|
13948
|
+
if (value.length > 0) searchParams.set(key, value.join(","));
|
|
13949
|
+
continue;
|
|
13950
|
+
}
|
|
13951
|
+
searchParams.set(key, String(value));
|
|
13952
|
+
}
|
|
13953
|
+
}
|
|
13230
13954
|
var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
|
|
13231
13955
|
var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
|
|
13232
13956
|
var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
|
|
@@ -13257,8 +13981,20 @@ function bodyInitFromSessionFileUpload(body) {
|
|
|
13257
13981
|
return body;
|
|
13258
13982
|
}
|
|
13259
13983
|
var EFFECT_CATALOG_SYNC_TIMEOUT_MS = 12e4;
|
|
13984
|
+
var EFFECT_CATALOG_SYNC_BATCH_SIZE = 20;
|
|
13260
13985
|
var EFFECT_CATALOG_SYNC_RETRY_COUNT = 3;
|
|
13261
13986
|
var EFFECT_CATALOG_SYNC_RETRY_DELAY_MS = 1e3;
|
|
13987
|
+
function chunkItems(items, batchSize) {
|
|
13988
|
+
const chunks = [];
|
|
13989
|
+
for (let offset = 0; offset < items.length; offset += batchSize) {
|
|
13990
|
+
chunks.push(items.slice(offset, offset + batchSize));
|
|
13991
|
+
}
|
|
13992
|
+
return chunks;
|
|
13993
|
+
}
|
|
13994
|
+
function isUnsupportedEffectCatalogMutation(error) {
|
|
13995
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13996
|
+
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");
|
|
13997
|
+
}
|
|
13262
13998
|
function planRecordObjectsChunks(records, batchSize) {
|
|
13263
13999
|
const total = records.length;
|
|
13264
14000
|
const size = Math.max(1, Math.min(batchSize, total));
|
|
@@ -13270,6 +14006,23 @@ function planRecordObjectsChunks(records, batchSize) {
|
|
|
13270
14006
|
}
|
|
13271
14007
|
return plans;
|
|
13272
14008
|
}
|
|
14009
|
+
function preserveRecordObjectRealId(record) {
|
|
14010
|
+
const realId = record.id.trim();
|
|
14011
|
+
if (!realId) {
|
|
14012
|
+
return record;
|
|
14013
|
+
}
|
|
14014
|
+
const fields = record.fields || {};
|
|
14015
|
+
if (typeof fields.real_id === "string" && fields.real_id.trim()) {
|
|
14016
|
+
return record;
|
|
14017
|
+
}
|
|
14018
|
+
return {
|
|
14019
|
+
...record,
|
|
14020
|
+
fields: {
|
|
14021
|
+
...fields,
|
|
14022
|
+
real_id: realId
|
|
14023
|
+
}
|
|
14024
|
+
};
|
|
14025
|
+
}
|
|
13273
14026
|
function computeEffectKey2(effect) {
|
|
13274
14027
|
const attachedClass = effect.className?.trim();
|
|
13275
14028
|
if (!attachedClass) {
|
|
@@ -13507,11 +14260,105 @@ var Environment = class _Environment {
|
|
|
13507
14260
|
getAwaitingCount: async () => this.getAwaitingRecordCount()
|
|
13508
14261
|
};
|
|
13509
14262
|
}
|
|
14263
|
+
/**
|
|
14264
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14265
|
+
* own the customer application's state machine.
|
|
14266
|
+
*/
|
|
14267
|
+
async recordState(input) {
|
|
14268
|
+
const { machine, state, ...target } = input;
|
|
14269
|
+
if (!machine.trim()) {
|
|
14270
|
+
throw new Error("State update requires a machine name");
|
|
14271
|
+
}
|
|
14272
|
+
if (!state.trim()) {
|
|
14273
|
+
throw new Error("State update requires a state");
|
|
14274
|
+
}
|
|
14275
|
+
return this.recordObject({
|
|
14276
|
+
className: target.className,
|
|
14277
|
+
id: target.id,
|
|
14278
|
+
...target.label ? { label: target.label } : {},
|
|
14279
|
+
...target.fields ? { fields: target.fields } : {},
|
|
14280
|
+
...target.relationships ? { relationships: target.relationships } : {},
|
|
14281
|
+
states: {
|
|
14282
|
+
[machine.trim()]: {
|
|
14283
|
+
state: state.trim(),
|
|
14284
|
+
...target.source ? { source: target.source } : {},
|
|
14285
|
+
...target.cause ? { cause: target.cause } : {},
|
|
14286
|
+
...target.actorId ? { actorId: target.actorId } : {},
|
|
14287
|
+
...target.observedAt !== void 0 ? { observedAt: target.observedAt } : {},
|
|
14288
|
+
...target.force !== void 0 ? { force: target.force } : {},
|
|
14289
|
+
...target.metadata ? { metadata: target.metadata } : {}
|
|
14290
|
+
}
|
|
14291
|
+
}
|
|
14292
|
+
});
|
|
14293
|
+
}
|
|
14294
|
+
/**
|
|
14295
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14296
|
+
* own the customer application's state machine.
|
|
14297
|
+
*
|
|
14298
|
+
* Example:
|
|
14299
|
+
* `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
|
|
14300
|
+
*/
|
|
14301
|
+
state(target) {
|
|
14302
|
+
const observe = async (machineName, stateName, input = {}) => {
|
|
14303
|
+
const observedState = input.observedState || input.state || stateName;
|
|
14304
|
+
if (!observedState) {
|
|
14305
|
+
throw new Error("State observation requires a target state");
|
|
14306
|
+
}
|
|
14307
|
+
return this.recordState({
|
|
14308
|
+
...target,
|
|
14309
|
+
machine: machineName,
|
|
14310
|
+
state: observedState,
|
|
14311
|
+
...input.source ? { source: input.source } : {},
|
|
14312
|
+
...input.cause ? { cause: input.cause } : {},
|
|
14313
|
+
...input.actorId ? { actorId: input.actorId } : {},
|
|
14314
|
+
...input.observedAt !== void 0 ? { observedAt: input.observedAt } : {},
|
|
14315
|
+
...input.force !== void 0 ? { force: input.force } : {},
|
|
14316
|
+
...input.metadata ? { metadata: input.metadata } : {}
|
|
14317
|
+
});
|
|
14318
|
+
};
|
|
14319
|
+
return new Proxy(
|
|
14320
|
+
{},
|
|
14321
|
+
{
|
|
14322
|
+
get: (_target, machineProperty) => {
|
|
14323
|
+
if (typeof machineProperty !== "string") return void 0;
|
|
14324
|
+
return new Proxy(
|
|
14325
|
+
{},
|
|
14326
|
+
{
|
|
14327
|
+
get: (_machineTarget, stateProperty) => {
|
|
14328
|
+
if (stateProperty === "to") {
|
|
14329
|
+
return (stateName, input) => observe(machineProperty, stateName, input || {});
|
|
14330
|
+
}
|
|
14331
|
+
if (typeof stateProperty !== "string") return void 0;
|
|
14332
|
+
return (input) => observe(
|
|
14333
|
+
machineProperty,
|
|
14334
|
+
stateNameFromMethodName(stateProperty),
|
|
14335
|
+
input || {}
|
|
14336
|
+
);
|
|
14337
|
+
}
|
|
14338
|
+
}
|
|
14339
|
+
);
|
|
14340
|
+
}
|
|
14341
|
+
}
|
|
14342
|
+
);
|
|
14343
|
+
}
|
|
13510
14344
|
get feedback() {
|
|
13511
14345
|
return {
|
|
13512
14346
|
list: async () => this.listFeedback()
|
|
13513
14347
|
};
|
|
13514
14348
|
}
|
|
14349
|
+
get manualActions() {
|
|
14350
|
+
return {
|
|
14351
|
+
record: (input) => this.recordManualAction(input),
|
|
14352
|
+
list: (options = {}) => this.listManualActions(options),
|
|
14353
|
+
suggest: (options = {}) => this.suggestManualActions(options)
|
|
14354
|
+
};
|
|
14355
|
+
}
|
|
14356
|
+
get artifactApprovals() {
|
|
14357
|
+
return {
|
|
14358
|
+
list: (options = {}) => this.listArtifactApprovals(options),
|
|
14359
|
+
decide: (approvalTaskId, input) => this.decideArtifactApproval(approvalTaskId, input)
|
|
14360
|
+
};
|
|
14361
|
+
}
|
|
13515
14362
|
/**
|
|
13516
14363
|
* Sessionless environments do not own a live transport, so disconnecting the
|
|
13517
14364
|
* environment handle itself is a no-op. This keeps the public surface
|
|
@@ -13590,6 +14437,50 @@ var Environment = class _Environment {
|
|
|
13590
14437
|
const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
|
|
13591
14438
|
return Array.isArray(response.items) ? response.items : [];
|
|
13592
14439
|
}
|
|
14440
|
+
async recordManualAction(input) {
|
|
14441
|
+
const body = {
|
|
14442
|
+
...input,
|
|
14443
|
+
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
|
|
14444
|
+
};
|
|
14445
|
+
return this.controlPlaneRequest(
|
|
14446
|
+
`/control/environments/${this.environmentId}/manual-actions`,
|
|
14447
|
+
{
|
|
14448
|
+
method: "POST",
|
|
14449
|
+
body: JSON.stringify(body)
|
|
14450
|
+
}
|
|
14451
|
+
);
|
|
14452
|
+
}
|
|
14453
|
+
async listManualActions(options = {}) {
|
|
14454
|
+
const query = new URLSearchParams();
|
|
14455
|
+
appendQueryOptions(query, options);
|
|
14456
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14457
|
+
return this.controlPlaneRequest(`/control/environments/${this.environmentId}/manual-actions${suffix}`);
|
|
14458
|
+
}
|
|
14459
|
+
async suggestManualActions(options = {}) {
|
|
14460
|
+
const query = new URLSearchParams();
|
|
14461
|
+
appendQueryOptions(query, options);
|
|
14462
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14463
|
+
return this.controlPlaneRequest(
|
|
14464
|
+
`/control/environments/${this.environmentId}/manual-actions/suggestions${suffix}`
|
|
14465
|
+
);
|
|
14466
|
+
}
|
|
14467
|
+
async listArtifactApprovals(options = {}) {
|
|
14468
|
+
const query = new URLSearchParams();
|
|
14469
|
+
appendQueryOptions(query, options);
|
|
14470
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14471
|
+
return this.controlPlaneRequest(
|
|
14472
|
+
`/control/environments/${this.environmentId}/artifact-approvals${suffix}`
|
|
14473
|
+
);
|
|
14474
|
+
}
|
|
14475
|
+
async decideArtifactApproval(approvalTaskId, input) {
|
|
14476
|
+
return this.controlPlaneRequest(
|
|
14477
|
+
`/control/environments/${this.environmentId}/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
14478
|
+
{
|
|
14479
|
+
method: "POST",
|
|
14480
|
+
body: JSON.stringify(input)
|
|
14481
|
+
}
|
|
14482
|
+
);
|
|
14483
|
+
}
|
|
13593
14484
|
getRuntimeBaseUrl() {
|
|
13594
14485
|
return deriveRuntimeBaseUrl(this._apiEndpoint);
|
|
13595
14486
|
}
|
|
@@ -14414,10 +15305,11 @@ var Environment = class _Environment {
|
|
|
14414
15305
|
if (!Array.isArray(records) || records.length === 0) {
|
|
14415
15306
|
return [];
|
|
14416
15307
|
}
|
|
15308
|
+
const recordsToWrite = records.map(preserveRecordObjectRealId);
|
|
14417
15309
|
const batchSize = Math.max(
|
|
14418
15310
|
1,
|
|
14419
15311
|
Math.min(
|
|
14420
|
-
|
|
15312
|
+
recordsToWrite.length,
|
|
14421
15313
|
options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
|
|
14422
15314
|
)
|
|
14423
15315
|
);
|
|
@@ -14425,8 +15317,8 @@ var Environment = class _Environment {
|
|
|
14425
15317
|
MAX_RECORD_OBJECTS_CONCURRENCY,
|
|
14426
15318
|
Math.max(1, options?.concurrency ?? 1)
|
|
14427
15319
|
);
|
|
14428
|
-
const plans = planRecordObjectsChunks(
|
|
14429
|
-
const total =
|
|
15320
|
+
const plans = planRecordObjectsChunks(recordsToWrite, batchSize);
|
|
15321
|
+
const total = recordsToWrite.length;
|
|
14430
15322
|
const results = new Array(total);
|
|
14431
15323
|
const onChunk = options?.onChunkComplete;
|
|
14432
15324
|
for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
|
|
@@ -14497,12 +15389,13 @@ var Environment = class _Environment {
|
|
|
14497
15389
|
* synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
|
|
14498
15390
|
*/
|
|
14499
15391
|
async enqueueRecordImport(records, options = {}) {
|
|
15392
|
+
const recordsToImport = records.map(preserveRecordObjectRealId);
|
|
14500
15393
|
return this.controlPlaneRequest(
|
|
14501
15394
|
`/control/environments/${this.environmentId}/record-imports`,
|
|
14502
15395
|
{
|
|
14503
15396
|
method: "POST",
|
|
14504
15397
|
body: JSON.stringify({
|
|
14505
|
-
records,
|
|
15398
|
+
records: recordsToImport,
|
|
14506
15399
|
batchSize: options.batchSize,
|
|
14507
15400
|
setupRunId: options.setupRunId,
|
|
14508
15401
|
writeMode: options.writeMode
|
|
@@ -14610,11 +15503,7 @@ var EnvironmentSession = class extends Session {
|
|
|
14610
15503
|
}
|
|
14611
15504
|
buildSessionDataUrl(path, query) {
|
|
14612
15505
|
const searchParams = new URLSearchParams();
|
|
14613
|
-
|
|
14614
|
-
if (value !== null && typeof value !== "undefined" && value !== "") {
|
|
14615
|
-
searchParams.set(key, String(value));
|
|
14616
|
-
}
|
|
14617
|
-
}
|
|
15506
|
+
appendQueryOptions(searchParams, query);
|
|
14618
15507
|
const queryString = searchParams.toString();
|
|
14619
15508
|
return `${this.environment.runtimeBaseUrl}${this.sessionDataRoutePrefix}/${encodeURIComponent(this.sessionId)}${path}${queryString ? `?${queryString}` : ""}`;
|
|
14620
15509
|
}
|
|
@@ -14697,9 +15586,108 @@ var EnvironmentSession = class extends Session {
|
|
|
14697
15586
|
),
|
|
14698
15587
|
get: (jobId) => this.sessionDataRequest(
|
|
14699
15588
|
`/jobs/${encodeURIComponent(jobId)}`
|
|
15589
|
+
),
|
|
15590
|
+
latest: async (options = {}) => {
|
|
15591
|
+
const page = await this.sessionDataRequest("/jobs", {
|
|
15592
|
+
status: options.status || "all",
|
|
15593
|
+
latest: true,
|
|
15594
|
+
limit: 1
|
|
15595
|
+
});
|
|
15596
|
+
return page.items[0] || null;
|
|
15597
|
+
}
|
|
15598
|
+
};
|
|
15599
|
+
}
|
|
15600
|
+
get artifacts() {
|
|
15601
|
+
return {
|
|
15602
|
+
list: (options = {}) => {
|
|
15603
|
+
const queryOptions = { ...options };
|
|
15604
|
+
if (options.target) {
|
|
15605
|
+
queryOptions.targetClassName = options.target.className;
|
|
15606
|
+
queryOptions.targetId = options.target.id;
|
|
15607
|
+
delete queryOptions.target;
|
|
15608
|
+
}
|
|
15609
|
+
return this.sessionDataRequest("/artifacts", queryOptions);
|
|
15610
|
+
},
|
|
15611
|
+
listForLatestJob: (options = {}) => this.artifacts.list({
|
|
15612
|
+
...options,
|
|
15613
|
+
latestJob: true
|
|
15614
|
+
}),
|
|
15615
|
+
get: (artifactId) => this.sessionDataRequest(
|
|
15616
|
+
`/artifacts/${encodeURIComponent(artifactId)}`
|
|
15617
|
+
),
|
|
15618
|
+
create: (artifact) => this.sessionDataRequest(
|
|
15619
|
+
"/artifacts",
|
|
15620
|
+
void 0,
|
|
15621
|
+
{
|
|
15622
|
+
method: "POST",
|
|
15623
|
+
body: artifact
|
|
15624
|
+
}
|
|
15625
|
+
),
|
|
15626
|
+
updateInputs: (artifactId, patch) => this.sessionDataRequest(
|
|
15627
|
+
`/artifacts/${encodeURIComponent(artifactId)}`,
|
|
15628
|
+
void 0,
|
|
15629
|
+
{
|
|
15630
|
+
method: "PATCH",
|
|
15631
|
+
body: patch
|
|
15632
|
+
}
|
|
15633
|
+
),
|
|
15634
|
+
validate: (artifactId) => this.sessionDataRequest(
|
|
15635
|
+
`/artifacts/${encodeURIComponent(artifactId)}/validate`,
|
|
15636
|
+
void 0,
|
|
15637
|
+
{ method: "POST" }
|
|
15638
|
+
),
|
|
15639
|
+
execute: (artifactId, options) => this.sessionDataRequest(
|
|
15640
|
+
`/artifacts/${encodeURIComponent(artifactId)}/execute`,
|
|
15641
|
+
void 0,
|
|
15642
|
+
{ method: "POST", body: options }
|
|
15643
|
+
),
|
|
15644
|
+
approve: (artifactId, options) => this.sessionDataRequest(
|
|
15645
|
+
`/artifacts/${encodeURIComponent(artifactId)}/approve`,
|
|
15646
|
+
void 0,
|
|
15647
|
+
{ method: "POST", body: options }
|
|
15648
|
+
),
|
|
15649
|
+
cancel: (artifactId) => this.sessionDataRequest(
|
|
15650
|
+
`/artifacts/${encodeURIComponent(artifactId)}/cancel`,
|
|
15651
|
+
void 0,
|
|
15652
|
+
{ method: "POST" }
|
|
14700
15653
|
)
|
|
14701
15654
|
};
|
|
14702
15655
|
}
|
|
15656
|
+
get manualActions() {
|
|
15657
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15658
|
+
return {
|
|
15659
|
+
record: (input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15660
|
+
"/manual-actions",
|
|
15661
|
+
void 0,
|
|
15662
|
+
{
|
|
15663
|
+
method: "POST",
|
|
15664
|
+
body: { ...input, sessionId: this.sessionId }
|
|
15665
|
+
}
|
|
15666
|
+
) : this.environment.manualActions.record({
|
|
15667
|
+
...input,
|
|
15668
|
+
sessionId: this.sessionId
|
|
15669
|
+
}),
|
|
15670
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/manual-actions", { ...options, sessionId: this.sessionId }) : this.environment.manualActions.list({
|
|
15671
|
+
...options,
|
|
15672
|
+
sessionId: this.sessionId
|
|
15673
|
+
}),
|
|
15674
|
+
suggest: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15675
|
+
"/manual-actions/suggestions",
|
|
15676
|
+
options
|
|
15677
|
+
) : this.environment.manualActions.suggest(options)
|
|
15678
|
+
};
|
|
15679
|
+
}
|
|
15680
|
+
get artifactApprovals() {
|
|
15681
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15682
|
+
return {
|
|
15683
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/artifact-approvals", options) : this.environment.artifactApprovals.list(options),
|
|
15684
|
+
decide: (approvalTaskId, input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15685
|
+
`/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
15686
|
+
void 0,
|
|
15687
|
+
{ method: "POST", body: input }
|
|
15688
|
+
) : this.environment.artifactApprovals.decide(approvalTaskId, input)
|
|
15689
|
+
};
|
|
15690
|
+
}
|
|
14703
15691
|
get files() {
|
|
14704
15692
|
return {
|
|
14705
15693
|
list: (options = {}) => this.sessionDataRequest(
|
|
@@ -14780,13 +15768,16 @@ var EnvironmentSession = class extends Session {
|
|
|
14780
15768
|
get transcript() {
|
|
14781
15769
|
return {
|
|
14782
15770
|
list: async (options = {}) => {
|
|
14783
|
-
const [messages, jobs, entries, lists] = await Promise.all([
|
|
15771
|
+
const [messages, jobs, entries, lists, artifacts] = await Promise.all([
|
|
14784
15772
|
this.collectAllSessionItems(this.messages.list),
|
|
14785
15773
|
this.collectAllSessionItems(
|
|
14786
15774
|
(pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
|
|
14787
15775
|
),
|
|
14788
15776
|
this.collectAllSessionItems(this.heap.entries.list),
|
|
14789
|
-
this.collectAllSessionItems(this.heap.lists.list)
|
|
15777
|
+
this.collectAllSessionItems(this.heap.lists.list),
|
|
15778
|
+
this.collectAllSessionItems(
|
|
15779
|
+
(pageOptions) => this.artifacts.list({ ...pageOptions, status: "all" })
|
|
15780
|
+
)
|
|
14790
15781
|
]);
|
|
14791
15782
|
const liveDoc = {
|
|
14792
15783
|
conversation: { messages },
|
|
@@ -14800,6 +15791,21 @@ var EnvironmentSession = class extends Session {
|
|
|
14800
15791
|
(entry) => Boolean(entry)
|
|
14801
15792
|
)
|
|
14802
15793
|
)
|
|
15794
|
+
},
|
|
15795
|
+
artifacts: {
|
|
15796
|
+
byId: Object.fromEntries(
|
|
15797
|
+
artifacts.map((artifact) => {
|
|
15798
|
+
return artifact?.artifactId ? [
|
|
15799
|
+
artifact.artifactId,
|
|
15800
|
+
artifact
|
|
15801
|
+
] : null;
|
|
15802
|
+
}).filter(
|
|
15803
|
+
(entry) => Boolean(entry)
|
|
15804
|
+
)
|
|
15805
|
+
),
|
|
15806
|
+
order: artifacts.map((artifact) => artifact?.artifactId).filter(
|
|
15807
|
+
(artifactId) => Boolean(artifactId)
|
|
15808
|
+
)
|
|
14803
15809
|
}
|
|
14804
15810
|
};
|
|
14805
15811
|
const heap = normalizeHeapSnapshot({
|
|
@@ -14876,6 +15882,12 @@ var EnvironmentSession = class extends Session {
|
|
|
14876
15882
|
async recordObject(options) {
|
|
14877
15883
|
return this.environment.recordObject(options);
|
|
14878
15884
|
}
|
|
15885
|
+
async recordState(input) {
|
|
15886
|
+
return this.environment.recordState(input);
|
|
15887
|
+
}
|
|
15888
|
+
state(target) {
|
|
15889
|
+
return this.environment.state(target);
|
|
15890
|
+
}
|
|
14879
15891
|
async recordObjects(records, options) {
|
|
14880
15892
|
return this.environment.recordObjects(records, options);
|
|
14881
15893
|
}
|
|
@@ -15703,15 +16715,43 @@ var Granular = class _Granular {
|
|
|
15703
16715
|
const effects = Array.from(
|
|
15704
16716
|
this.getSandboxEffectMap(host.sandboxId).values()
|
|
15705
16717
|
).map((effect) => this.serializeEffect(effect));
|
|
15706
|
-
|
|
15707
|
-
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
16718
|
+
let acceptedCount = 0;
|
|
16719
|
+
const rejected = [];
|
|
16720
|
+
try {
|
|
16721
|
+
await withTimeout(
|
|
16722
|
+
host.wsClient.call("effects.resetCatalog", {}),
|
|
16723
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16724
|
+
`effects.resetCatalog for sandbox ${host.sandboxId}`
|
|
16725
|
+
);
|
|
16726
|
+
for (const batch of chunkItems(effects, EFFECT_CATALOG_SYNC_BATCH_SIZE)) {
|
|
16727
|
+
const result = await withTimeout(
|
|
16728
|
+
host.wsClient.call("effects.addCatalog", {
|
|
16729
|
+
effects: batch
|
|
16730
|
+
}),
|
|
16731
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16732
|
+
`effects.addCatalog for sandbox ${host.sandboxId}`
|
|
16733
|
+
);
|
|
16734
|
+
acceptedCount += typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16735
|
+
if (Array.isArray(result?.rejected)) {
|
|
16736
|
+
rejected.push(...result.rejected);
|
|
16737
|
+
}
|
|
16738
|
+
}
|
|
16739
|
+
} catch (error) {
|
|
16740
|
+
if (!isUnsupportedEffectCatalogMutation(error)) {
|
|
16741
|
+
throw error;
|
|
16742
|
+
}
|
|
16743
|
+
const result = await withTimeout(
|
|
16744
|
+
host.wsClient.call("effects.publishCatalog", {
|
|
16745
|
+
effects
|
|
16746
|
+
}),
|
|
16747
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16748
|
+
`effects.publishCatalog for sandbox ${host.sandboxId}`
|
|
16749
|
+
);
|
|
16750
|
+
acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16751
|
+
if (Array.isArray(result?.rejected)) {
|
|
16752
|
+
rejected.push(...result.rejected);
|
|
16753
|
+
}
|
|
16754
|
+
}
|
|
15715
16755
|
if (acceptedCount === 0 && rejected.length > 0) {
|
|
15716
16756
|
const detail = rejected.map(
|
|
15717
16757
|
(entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`
|
|
@@ -16943,6 +17983,7 @@ var HARNESS_V3_FRONTEND_ACTIONS_MODULE = "@granular/actions/frontend";
|
|
|
16943
17983
|
var HARNESS_V3_CSV_MODULE = "@granular/utils/csv";
|
|
16944
17984
|
var HARNESS_V3_XLSX_MODULE = "@granular/utils/xlsx";
|
|
16945
17985
|
var LEGACY_SANDBOX_TOOLS_MODULE_PATTERN = "\\.\\/sandbox-tools(?:\\.js)?";
|
|
17986
|
+
var HARNESS_V3_RUNTIME_MODULE_PATTERN = "@granular/(?:agent|session|domain(?:/[A-Za-z_$][\\w$]*)?|actions/(?:backend|frontend)|utils/(?:csv|xlsx))";
|
|
16946
17987
|
function hasNamedModuleImport(source, moduleName, name) {
|
|
16947
17988
|
const escapedModule = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16948
17989
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -17001,6 +18042,15 @@ function reviewGeneratedJobCode(code, _options = {}) {
|
|
|
17001
18042
|
message: "Generated code must use static top-level ESM imports from the Harness v3 runtime modules. Do not use dynamic import(...)."
|
|
17002
18043
|
});
|
|
17003
18044
|
}
|
|
18045
|
+
if (new RegExp(
|
|
18046
|
+
`import\\s+\\*\\s+as\\s+[A-Za-z_$][\\w$]*\\s+from\\s*['"]${HARNESS_V3_RUNTIME_MODULE_PATTERN}['"]`
|
|
18047
|
+
).test(normalized)) {
|
|
18048
|
+
issues.push({
|
|
18049
|
+
code: "runtime_namespace_import",
|
|
18050
|
+
severity: "error",
|
|
18051
|
+
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"`.'
|
|
18052
|
+
});
|
|
18053
|
+
}
|
|
17004
18054
|
if (/\bprocess\.exit\s*\(/.test(normalized)) {
|
|
17005
18055
|
issues.push({
|
|
17006
18056
|
code: "process_exit",
|
|
@@ -18025,6 +19075,31 @@ function buildGranularAgentHeapBlock(heapSummary) {
|
|
|
18025
19075
|
entries: {}
|
|
18026
19076
|
});
|
|
18027
19077
|
}
|
|
19078
|
+
function buildGranularAgentManualActionMemorySummary(input) {
|
|
19079
|
+
const maxItems = Math.max(1, Math.min(12, input.maxItems ?? 8));
|
|
19080
|
+
const suggestions = (input.suggestions || []).filter((suggestion) => suggestion?.actionKey).slice(0, maxItems).map((suggestion) => ({
|
|
19081
|
+
actionKey: suggestion.actionKey,
|
|
19082
|
+
label: suggestion.label || null,
|
|
19083
|
+
targetClassName: suggestion.targetClassName || null,
|
|
19084
|
+
count: typeof suggestion.count === "number" && Number.isFinite(suggestion.count) ? suggestion.count : null,
|
|
19085
|
+
subjectCount: typeof suggestion.subjectCount === "number" && Number.isFinite(suggestion.subjectCount) ? suggestion.subjectCount : null,
|
|
19086
|
+
successCount: typeof suggestion.successCount === "number" && Number.isFinite(suggestion.successCount) ? suggestion.successCount : null,
|
|
19087
|
+
failureCount: typeof suggestion.failureCount === "number" && Number.isFinite(suggestion.failureCount) ? suggestion.failureCount : null,
|
|
19088
|
+
lastOccurredAt: typeof suggestion.lastOccurredAt === "number" && Number.isFinite(suggestion.lastOccurredAt) ? suggestion.lastOccurredAt : null,
|
|
19089
|
+
sampleTargetIds: Array.isArray(suggestion.sampleTargetIds) ? suggestion.sampleTargetIds.filter(
|
|
19090
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
19091
|
+
).slice(0, 6) : []
|
|
19092
|
+
}));
|
|
19093
|
+
return [
|
|
19094
|
+
renderConstBlock("manualActionMemory", {
|
|
19095
|
+
suggestions
|
|
19096
|
+
}),
|
|
19097
|
+
"Use manualActionMemory only as behavioral context for likely next actions. Ground the current target and validate permissions before creating or running prepared actions."
|
|
19098
|
+
].join("\n");
|
|
19099
|
+
}
|
|
19100
|
+
function buildGranularAgentManualActionBlock(manualActionSummary) {
|
|
19101
|
+
return manualActionSummary?.trim() || buildGranularAgentManualActionMemorySummary({ suggestions: [] });
|
|
19102
|
+
}
|
|
18028
19103
|
function projectSessionFileSummary(liveDoc) {
|
|
18029
19104
|
const files = asRecord4(liveDoc?.files);
|
|
18030
19105
|
const byId = asRecord4(files?.byId) || {};
|
|
@@ -18056,8 +19131,12 @@ function buildGranularAgentFileBlock(fileSummary) {
|
|
|
18056
19131
|
function extractRuntimeContractExports(domainBlock) {
|
|
18057
19132
|
const classes = /* @__PURE__ */ new Set();
|
|
18058
19133
|
const actions = /* @__PURE__ */ new Set();
|
|
18059
|
-
const
|
|
18060
|
-
for (const match of domainBlock.matchAll(
|
|
19134
|
+
const classConstPattern = /export\s+declare\s+const\s+([A-Za-z_$][\w$]*)\s*:\s*EntityClass\b/g;
|
|
19135
|
+
for (const match of domainBlock.matchAll(classConstPattern)) {
|
|
19136
|
+
classes.add(match[1]);
|
|
19137
|
+
}
|
|
19138
|
+
const classDeclPattern = /export\s+declare\s+class\s+([A-Za-z_$][\w$]*)\b/g;
|
|
19139
|
+
for (const match of domainBlock.matchAll(classDeclPattern)) {
|
|
18061
19140
|
classes.add(match[1]);
|
|
18062
19141
|
}
|
|
18063
19142
|
const actionPattern = /export\s+declare\s+function\s+([A-Za-z_$][\w$]*)/g;
|
|
@@ -18562,6 +19641,9 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18562
19641
|
});
|
|
18563
19642
|
const referentBlock = buildGranularAgentReferentBlock(input.referentSummary);
|
|
18564
19643
|
const loopBlock = buildGranularAgentLoopBlock(input.loopSummary);
|
|
19644
|
+
const manualActionBlock = buildGranularAgentManualActionBlock(
|
|
19645
|
+
input.manualActionSummary
|
|
19646
|
+
);
|
|
18565
19647
|
const knownFactsBlock = renderConstBlock(
|
|
18566
19648
|
"knownFacts",
|
|
18567
19649
|
buildKnownFactsFromCheckpoint(input.checkpoint)
|
|
@@ -18575,16 +19657,15 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18575
19657
|
- \`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.
|
|
18576
19658
|
- 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.
|
|
18577
19659
|
- 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.
|
|
18578
|
-
- When \`replyToUser(...)\` mentions a grounded record that should remain clickable/referable, wrap only the visible record label in a self-closing inline reference tag
|
|
18579
|
-
- Treat \`showObjects(...)\` as the UI display call for user-visible records,
|
|
18580
|
-
-
|
|
18581
|
-
-
|
|
18582
|
-
-
|
|
18583
|
-
-
|
|
19660
|
+
- 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.
|
|
19661
|
+
- 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"] })\`.
|
|
19662
|
+
- \`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(...)\`.
|
|
19663
|
+
- 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.
|
|
19664
|
+
- 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()\`.
|
|
19665
|
+
- 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.
|
|
18584
19666
|
- 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.
|
|
18585
19667
|
- 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.
|
|
18586
|
-
-
|
|
18587
|
-
- 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.
|
|
19668
|
+
- 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.
|
|
18588
19669
|
- 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\`.
|
|
18589
19670
|
- \`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.
|
|
18590
19671
|
- 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,7 +19676,7 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18595
19676
|
- When using code, assistant text must be empty or one brief summary.
|
|
18596
19677
|
- Code must be plain runnable JavaScript with top-level await.
|
|
18597
19678
|
- Use [Runtime Imports] as the authoritative module map. Import only listed module exports.
|
|
18598
|
-
- 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.
|
|
19679
|
+
- 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.
|
|
18599
19680
|
- 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.
|
|
18600
19681
|
- 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.
|
|
18601
19682
|
- 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\`.
|
|
@@ -18658,6 +19739,7 @@ ${workflowRules}
|
|
|
18658
19739
|
High-priority execution rules:
|
|
18659
19740
|
- 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.
|
|
18660
19741
|
- 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.
|
|
19742
|
+
- 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.
|
|
18661
19743
|
- 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.
|
|
18662
19744
|
- 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.
|
|
18663
19745
|
- 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.
|
|
@@ -18701,7 +19783,7 @@ Intent resolution:
|
|
|
18701
19783
|
- 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.
|
|
18702
19784
|
- 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.
|
|
18703
19785
|
- 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.
|
|
18704
|
-
- 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
|
|
19786
|
+
- 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.
|
|
18705
19787
|
- 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.
|
|
18706
19788
|
- Never call \`.get({ path: "" })\`; an empty path is not a saved reference.
|
|
18707
19789
|
- 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.
|
|
@@ -18828,20 +19910,10 @@ Ask the user when:
|
|
|
18828
19910
|
- the target is unique but the requested action is unclear
|
|
18829
19911
|
|
|
18830
19912
|
Relationship filters:
|
|
18831
|
-
-
|
|
18832
|
-
-
|
|
18833
|
-
-
|
|
18834
|
-
-
|
|
18835
|
-
- 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.
|
|
18836
|
-
- 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.
|
|
18837
|
-
- Use \`some\` only when the generated TypeScript type says \`ManyRelationFilter\`.
|
|
18838
|
-
- 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.
|
|
18839
|
-
- Use \`{ relationship: { id: "record_id" } }\` or \`{ relationship: { path: "class_record_id" } }\` when matching a known related record.
|
|
18840
|
-
- 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\`.
|
|
18841
|
-
- 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.
|
|
18842
|
-
- Use \`{ relationship: { is: { field: { equal_to: value } } } }\` only for nested field filters. Never put \`id\` or \`path\` inside \`is\`.
|
|
18843
|
-
- 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.
|
|
18844
|
-
- Do not pass a full record instance into a filter; if you already fetched a record, filter by its id or path instead.
|
|
19913
|
+
- Use the generated filter type as the authority: \`OneRelationFilter\` supports \`id\`, \`path\`, \`is\`, \`null\`, \`not_null\`; \`ManyRelationFilter\` supports those plus \`some\`.
|
|
19914
|
+
- Use \`id\` or \`path\` for a known related record; use \`is\` or \`some\` only for nested target-field filters.
|
|
19915
|
+
- 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.
|
|
19916
|
+
- Never pass a full record instance into a filter. Use its id/path or a declared relationship getter.
|
|
18845
19917
|
${domainSections.docs ? `
|
|
18846
19918
|
Domain notes:
|
|
18847
19919
|
${domainSections.docs}
|
|
@@ -18852,6 +19924,23 @@ ${actionIndex}
|
|
|
18852
19924
|
- 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.
|
|
18853
19925
|
- 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(...)\`.
|
|
18854
19926
|
- Actions listed under "Class-level" are class/static methods. Call them on the imported class, e.g. \`await Item.action_name(...)\`.
|
|
19927
|
+
- 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.
|
|
19928
|
+
- For pure field-collection requests, target the class-level entry state handle; for submit/review requests, target the nearest requested later state.
|
|
19929
|
+
- Choose the nearest target state that matches the user's words. Do not aim at a later state just because it is reachable.
|
|
19930
|
+
- 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\`.
|
|
19931
|
+
- 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.
|
|
19932
|
+
- 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.
|
|
19933
|
+
- 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()\`.
|
|
19934
|
+
- 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.
|
|
19935
|
+
- 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.
|
|
19936
|
+
- 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.
|
|
19937
|
+
- 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.
|
|
19938
|
+
- 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.
|
|
19939
|
+
- 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.
|
|
19940
|
+
- 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.
|
|
19941
|
+
- 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.
|
|
19942
|
+
- 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.
|
|
19943
|
+
- Use \`await prepared.show()\` or \`await actions.show(prepared)\` only to display an already-created prepared action again.
|
|
18855
19944
|
- 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.
|
|
18856
19945
|
- Never call a record-level action as \`Class.action_name(...)\`; that method will not exist.
|
|
18857
19946
|
- 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.
|
|
@@ -18882,6 +19971,8 @@ ${loopBlock}
|
|
|
18882
19971
|
|
|
18883
19972
|
${knownFactsBlock}
|
|
18884
19973
|
|
|
19974
|
+
${manualActionBlock}
|
|
19975
|
+
|
|
18885
19976
|
[Request]
|
|
18886
19977
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
18887
19978
|
}
|
|
@@ -19169,6 +20260,6 @@ function calculateOpenAITokenSpend(model, rawUsage) {
|
|
|
19169
20260
|
};
|
|
19170
20261
|
}
|
|
19171
20262
|
|
|
19172
|
-
export { Environment, EnvironmentSession, Granular, OPENAI_MODEL_PRICING_USD_PER_MILLION, OntologyHandle, Session, WSClient, buildContinuationInstruction, buildContinuationInstructionFromTemplate, buildGranularAgentCheckpointBlock, buildGranularAgentDomainBlock, buildGranularAgentFileBlock, buildGranularAgentHeapBlock, buildGranularAgentLoopBlock, buildGranularAgentReferentBlock, buildGranularAgentRuntimeImportsBlock, buildGranularAgentSessionBlock, buildGranularAgentSystemPrompt, buildGranularAgentSystemPromptFromTemplate, buildGranularAgentToolBlock, buildGranularAgentWorkflowBlock, buildOpenAISpendEventId, buildSessionTranscript, calculateOpenAITokenSpend, consumeGranularReasoningOnlyChunk, consumeGranularReasoningTraceChunk, createHarnessVerifierSnapshot, evaluateContinuation, extractPromptTokens, getCurrentClosureId, getDefaultHarnessTemplateId, getExclusivePromptTarget, getOpenAIModelPricing, hasOpenPrompt, hashHarnessTemplateValue, invokeRegisteredEffect, isLocalApiUrl, listHarnessTemplates, normalizeEffectBehaviors, normalizeOpenAIUsage, normalizePrompt, normalizePromptChoiceOption, normalizePromptText, normalizePromptType, projectConversationReferentFocus, projectConversationReferentSummary, projectHeapSummary, projectLoopSummary, projectSessionFileSummary, projectWorkflowFocus, projectWorkflowSummary, recordOpenAIUsageSpend, renderContinuationInstructionFromTemplate, renderGranularAgentSystemPromptFromTemplate, resolveApiUrl, resolveAuthTokenForApiUrl, resolveHarnessTemplate, resolveJobPresentation, resolvePromptAnswer, reviewGeneratedJobCode, scorePromptChoiceMatch, stripGranularReasoningTrace, toGranularHttpBase, validateHarnessTemplateManifest };
|
|
20263
|
+
export { Environment, EnvironmentSession, Granular, OPENAI_MODEL_PRICING_USD_PER_MILLION, OntologyHandle, Session, WSClient, buildContinuationInstruction, buildContinuationInstructionFromTemplate, buildGranularAgentCheckpointBlock, buildGranularAgentDomainBlock, buildGranularAgentFileBlock, buildGranularAgentHeapBlock, buildGranularAgentLoopBlock, buildGranularAgentManualActionBlock, buildGranularAgentManualActionMemorySummary, buildGranularAgentReferentBlock, buildGranularAgentRuntimeImportsBlock, buildGranularAgentSessionBlock, buildGranularAgentSystemPrompt, buildGranularAgentSystemPromptFromTemplate, buildGranularAgentToolBlock, buildGranularAgentWorkflowBlock, buildOpenAISpendEventId, buildSessionTranscript, calculateOpenAITokenSpend, consumeGranularReasoningOnlyChunk, consumeGranularReasoningTraceChunk, createHarnessVerifierSnapshot, evaluateContinuation, evaluateValidationRule, extractPromptTokens, getCurrentClosureId, getDefaultHarnessTemplateId, getExclusivePromptTarget, getOpenAIModelPricing, hasOpenPrompt, hashHarnessTemplateValue, invokeRegisteredEffect, isLocalApiUrl, listHarnessTemplates, normalizeEffectBehaviors, normalizeOpenAIUsage, normalizePrompt, normalizePromptChoiceOption, normalizePromptText, normalizePromptType, projectConversationReferentFocus, projectConversationReferentSummary, projectHeapSummary, projectLoopSummary, projectSessionFileSummary, projectWorkflowFocus, projectWorkflowSummary, recordOpenAIUsageSpend, renderContinuationInstructionFromTemplate, renderGranularAgentSystemPromptFromTemplate, resolveApiUrl, resolveAuthTokenForApiUrl, resolveHarnessTemplate, resolveJobPresentation, resolvePromptAnswer, reviewGeneratedJobCode, scorePromptChoiceMatch, stripGranularReasoningTrace, toGranularHttpBase, validateHarnessTemplateManifest, validationRuleFailureMessage };
|
|
19173
20264
|
//# sourceMappingURL=index.mjs.map
|
|
19174
20265
|
//# sourceMappingURL=index.mjs.map
|