@granular-software/sdk 0.4.48 → 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 +1110 -103
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +1110 -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 +1011 -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 +1192 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1189 -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.js
CHANGED
|
@@ -4038,6 +4038,9 @@ function rpcTimeoutMsForMethod(method) {
|
|
|
4038
4038
|
return DOMAIN_PACKAGE_RPC_TIMEOUT_MS;
|
|
4039
4039
|
case "client.heartbeat":
|
|
4040
4040
|
case "effects.publishCatalog":
|
|
4041
|
+
case "effects.resetCatalog":
|
|
4042
|
+
case "effects.addCatalog":
|
|
4043
|
+
case "effects.removeCatalog":
|
|
4041
4044
|
case "effects.refresh":
|
|
4042
4045
|
return EFFECT_CONTROL_RPC_TIMEOUT_MS;
|
|
4043
4046
|
case "harness.run":
|
|
@@ -4783,6 +4786,9 @@ function resolvePromptAnswer(prompt, answer) {
|
|
|
4783
4786
|
|
|
4784
4787
|
// src/session.ts
|
|
4785
4788
|
var PROMPT_TRANSCRIPT_APPEND_TIMEOUT_MS = 5e3;
|
|
4789
|
+
function toPascalCase(value) {
|
|
4790
|
+
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
4791
|
+
}
|
|
4786
4792
|
function withPromptTranscriptTimeout(promise) {
|
|
4787
4793
|
let timeout = null;
|
|
4788
4794
|
return Promise.race([
|
|
@@ -5345,9 +5351,7 @@ var Session = class {
|
|
|
5345
5351
|
if (classes && Object.keys(classes).length > 0) {
|
|
5346
5352
|
let docs2 = "# Domain Documentation\n\n";
|
|
5347
5353
|
docs2 += "Import concrete classes from `@granular/domain/<Class>` and global backend actions from `@granular/actions/backend`:\n\n";
|
|
5348
|
-
const classNames = Object.keys(classes).map(
|
|
5349
|
-
(c) => c.charAt(0).toUpperCase() + c.slice(1)
|
|
5350
|
-
);
|
|
5354
|
+
const classNames = Object.keys(classes).map(toPascalCase);
|
|
5351
5355
|
const globalNames = (globalTools || []).map((t) => t.name);
|
|
5352
5356
|
const importLines = [
|
|
5353
5357
|
...classNames.map(
|
|
@@ -5361,7 +5365,7 @@ ${importLines.join("\n") || "// No generated domain imports available."}
|
|
|
5361
5365
|
|
|
5362
5366
|
`;
|
|
5363
5367
|
for (const [className, cls] of Object.entries(classes)) {
|
|
5364
|
-
const TsName =
|
|
5368
|
+
const TsName = toPascalCase(className);
|
|
5365
5369
|
docs2 += `## ${TsName}
|
|
5366
5370
|
|
|
5367
5371
|
`;
|
|
@@ -5582,6 +5586,9 @@ import { ${tools[0]?.name || "example"} } from "@granular/actions/backend";
|
|
|
5582
5586
|
this.client.on("harness.model_stream", (data) => {
|
|
5583
5587
|
this.emit("harness:model_stream", data);
|
|
5584
5588
|
});
|
|
5589
|
+
this.client.on("harness.text_response.delta", (data) => {
|
|
5590
|
+
this.emit("harness:text_response_delta", data);
|
|
5591
|
+
});
|
|
5585
5592
|
this.client.on("job.agent_message", (data) => {
|
|
5586
5593
|
const normalized = normalizeJobAgentMessageEnvelope(data);
|
|
5587
5594
|
if (!normalized) return;
|
|
@@ -6348,6 +6355,28 @@ function asString(value) {
|
|
|
6348
6355
|
function trimString(value) {
|
|
6349
6356
|
return typeof value === "string" ? value.trim() : "";
|
|
6350
6357
|
}
|
|
6358
|
+
function compactJson(value, maxLength = 320) {
|
|
6359
|
+
if (value === void 0 || value === null) return void 0;
|
|
6360
|
+
try {
|
|
6361
|
+
const json = JSON.stringify(value);
|
|
6362
|
+
if (!json || json === "undefined") return void 0;
|
|
6363
|
+
return json.length > maxLength ? `${json.slice(0, maxLength)}...` : json;
|
|
6364
|
+
} catch {
|
|
6365
|
+
return String(value);
|
|
6366
|
+
}
|
|
6367
|
+
}
|
|
6368
|
+
function artifactRecordsById(liveDoc) {
|
|
6369
|
+
const artifacts = asRecord3(liveDoc?.artifacts);
|
|
6370
|
+
const byId = asRecord3(artifacts?.byId) || {};
|
|
6371
|
+
return Object.fromEntries(
|
|
6372
|
+
Object.entries(byId).map(([artifactId, value]) => {
|
|
6373
|
+
const record = asRecord3(value);
|
|
6374
|
+
return record ? [artifactId, record] : null;
|
|
6375
|
+
}).filter(
|
|
6376
|
+
(entry) => Boolean(entry)
|
|
6377
|
+
)
|
|
6378
|
+
);
|
|
6379
|
+
}
|
|
6351
6380
|
function normalizeShowRefs(value) {
|
|
6352
6381
|
const record = asRecord3(value);
|
|
6353
6382
|
if (!record) return void 0;
|
|
@@ -6364,9 +6393,31 @@ function normalizeShowRefs(value) {
|
|
|
6364
6393
|
entryPaths: normalizeRefs(record.entryPaths),
|
|
6365
6394
|
listNames: normalizeRefs(record.listNames),
|
|
6366
6395
|
variableNames: normalizeRefs(record.variableNames),
|
|
6367
|
-
fileIds: normalizeRefs(record.fileIds)
|
|
6396
|
+
fileIds: normalizeRefs(record.fileIds),
|
|
6397
|
+
sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
|
|
6398
|
+
actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
|
|
6368
6399
|
};
|
|
6369
|
-
return show.entryPaths || show.listNames || show.variableNames || show.fileIds ? show : void 0;
|
|
6400
|
+
return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions ? show : void 0;
|
|
6401
|
+
}
|
|
6402
|
+
function normalizeActionSuggestions(value) {
|
|
6403
|
+
if (!Array.isArray(value)) return void 0;
|
|
6404
|
+
const suggestions = [];
|
|
6405
|
+
for (const item of value) {
|
|
6406
|
+
const record = asRecord3(item);
|
|
6407
|
+
if (!record) continue;
|
|
6408
|
+
const label = trimString(record.label);
|
|
6409
|
+
if (!label) continue;
|
|
6410
|
+
const suggestionId = trimString(record.suggestionId) || trimString(record.id) || label;
|
|
6411
|
+
suggestions.push({
|
|
6412
|
+
suggestionId,
|
|
6413
|
+
label,
|
|
6414
|
+
...typeof record.description === "string" ? { description: record.description } : {},
|
|
6415
|
+
...asRecord3(record.artifact) ? { artifact: asRecord3(record.artifact) } : {},
|
|
6416
|
+
...asRecord3(record.target) ? { target: asRecord3(record.target) } : {},
|
|
6417
|
+
...asRecord3(record.metadata) ? { metadata: asRecord3(record.metadata) } : {}
|
|
6418
|
+
});
|
|
6419
|
+
}
|
|
6420
|
+
return suggestions.length ? suggestions : void 0;
|
|
6370
6421
|
}
|
|
6371
6422
|
function stringifyTranscriptValue(value, fallback = "") {
|
|
6372
6423
|
if (typeof value === "string") {
|
|
@@ -6386,12 +6437,139 @@ function stringifyTranscriptValue(value, fallback = "") {
|
|
|
6386
6437
|
return String(value);
|
|
6387
6438
|
}
|
|
6388
6439
|
}
|
|
6389
|
-
function
|
|
6440
|
+
function latestInputEditSummary(metadata) {
|
|
6441
|
+
const lastInputEdit = asRecord3(metadata.lastInputEdit);
|
|
6442
|
+
if (!lastInputEdit) return null;
|
|
6443
|
+
const source = asString(lastInputEdit.source) || "unknown";
|
|
6444
|
+
const actor = asString(lastInputEdit.actorSubjectId) || asString(lastInputEdit.actorPermissionProfileName) || asString(lastInputEdit.jobId) || null;
|
|
6445
|
+
const inputKeys = Array.isArray(lastInputEdit.changedInputKeys) ? lastInputEdit.changedInputKeys.filter(
|
|
6446
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6447
|
+
).slice(0, 6) : [];
|
|
6448
|
+
const relationshipKeys = Array.isArray(lastInputEdit.changedRelationshipKeys) ? lastInputEdit.changedRelationshipKeys.filter(
|
|
6449
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6450
|
+
).slice(0, 6) : [];
|
|
6451
|
+
const changed = [
|
|
6452
|
+
inputKeys.length ? `inputs=${inputKeys.join(",")}` : null,
|
|
6453
|
+
relationshipKeys.length ? `relationships=${relationshipKeys.join(",")}` : null
|
|
6454
|
+
].filter(Boolean);
|
|
6455
|
+
return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
|
|
6456
|
+
}
|
|
6457
|
+
function artifactIssueSummary(record) {
|
|
6458
|
+
const validation = asRecord3(record.validation);
|
|
6459
|
+
if (!validation) return null;
|
|
6460
|
+
const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
|
|
6461
|
+
if (issues.length > 0) {
|
|
6462
|
+
return `issues=${issues.map((issue) => {
|
|
6463
|
+
const code = asString(issue.code) || asString(issue.kind) || "issue";
|
|
6464
|
+
const path = asString(issue.path);
|
|
6465
|
+
const message = trimString(issue.message);
|
|
6466
|
+
return `${code}${path ? ` at ${path}` : ""}${message ? ` (${message})` : ""}`;
|
|
6467
|
+
}).join("; ")}`;
|
|
6468
|
+
}
|
|
6469
|
+
const error = trimString(validation.error) || trimString(validation.reason) || trimString(validation.message);
|
|
6470
|
+
return error ? `validation=${error}` : null;
|
|
6471
|
+
}
|
|
6472
|
+
function artifactExecutionSummary(metadata) {
|
|
6473
|
+
const execution = asRecord3(metadata.execution);
|
|
6474
|
+
if (!execution) return null;
|
|
6475
|
+
const result = asRecord3(execution.result);
|
|
6476
|
+
const awaiting = asString(result?.awaiting) || asString(execution.awaiting);
|
|
6477
|
+
const pendingTransition = asString(result?.pendingTransition) || asString(execution.pendingTransition);
|
|
6478
|
+
const approval = asRecord3(result?.approval) || asRecord3(execution.approval);
|
|
6479
|
+
const approvalTarget = asString(approval?.permissionProfileName) || asString(approval?.permissionProfileId) || asString(approval?.assigneeSubjectId);
|
|
6480
|
+
const error = trimString(execution.error);
|
|
6481
|
+
const pieces = [
|
|
6482
|
+
awaiting ? `awaiting=${awaiting}` : null,
|
|
6483
|
+
pendingTransition ? `pendingTransition=${pendingTransition}` : null,
|
|
6484
|
+
approvalTarget ? `approvalTarget=${approvalTarget}` : null,
|
|
6485
|
+
error ? `executionError=${error}` : null
|
|
6486
|
+
].filter(Boolean);
|
|
6487
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6488
|
+
}
|
|
6489
|
+
function artifactStatePathSummary(metadata) {
|
|
6490
|
+
const statePlan = asRecord3(metadata.statePlan);
|
|
6491
|
+
if (!statePlan) return null;
|
|
6492
|
+
const machineName = asString(statePlan.machineName);
|
|
6493
|
+
const targetState = asString(statePlan.targetState);
|
|
6494
|
+
const objectPath = asString(statePlan.objectPath);
|
|
6495
|
+
const approvedTransitions = Array.isArray(statePlan.approvedTransitions) ? statePlan.approvedTransitions.length : 0;
|
|
6496
|
+
const approvalDecisions = Array.isArray(statePlan.approvalDecisions) ? statePlan.approvalDecisions.length : 0;
|
|
6497
|
+
const pieces = [
|
|
6498
|
+
machineName || targetState ? `statePath=${machineName || "state_machine"}${targetState ? ` -> ${targetState}` : ""}` : null,
|
|
6499
|
+
objectPath ? `objectPath=${objectPath}` : null,
|
|
6500
|
+
approvedTransitions ? `approvedTransitions=${approvedTransitions}` : null,
|
|
6501
|
+
approvalDecisions ? `approvalDecisions=${approvalDecisions}` : null
|
|
6502
|
+
].filter(Boolean);
|
|
6503
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6504
|
+
}
|
|
6505
|
+
function artifactSummaryLine(artifactId, record) {
|
|
6506
|
+
if (!record) return `- ${artifactId}: unavailable in session artifact store`;
|
|
6507
|
+
const label = trimString(record.label) || artifactId;
|
|
6508
|
+
const kind = asString(record.kind) || "artifact";
|
|
6509
|
+
const status = asString(record.status) || "unknown";
|
|
6510
|
+
const createdByJobId = asString(record.createdByJobId);
|
|
6511
|
+
const target = asRecord3(record.target);
|
|
6512
|
+
const metadata = asRecord3(record.metadata) || {};
|
|
6513
|
+
const subArtifactIds = Array.isArray(record.subArtifactIds) ? record.subArtifactIds.filter(
|
|
6514
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
6515
|
+
).slice(0, 8) : [];
|
|
6516
|
+
const relationships = compactJson(record.relationships, 220);
|
|
6517
|
+
const pieces = [
|
|
6518
|
+
`kind=${kind}`,
|
|
6519
|
+
`status=${status}`,
|
|
6520
|
+
createdByJobId ? `createdByJob=${createdByJobId}` : null,
|
|
6521
|
+
target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
|
|
6522
|
+
artifactStatePathSummary(metadata),
|
|
6523
|
+
artifactExecutionSummary(metadata),
|
|
6524
|
+
artifactIssueSummary(record),
|
|
6525
|
+
latestInputEditSummary(metadata),
|
|
6526
|
+
subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
|
|
6527
|
+
relationships ? `relationships=${relationships}` : null
|
|
6528
|
+
].filter(Boolean);
|
|
6529
|
+
return `- ${artifactId}: ${label}${pieces.length ? `; ${pieces.join("; ")}` : ""}`;
|
|
6530
|
+
}
|
|
6531
|
+
function buildArtifactHistory(show, artifactsById) {
|
|
6390
6532
|
if (!show) return void 0;
|
|
6391
|
-
|
|
6533
|
+
const artifactIds = show.sessionArtifactIds || [];
|
|
6534
|
+
const actionSuggestions = show.actionSuggestions || [];
|
|
6535
|
+
if (artifactIds.length === 0 && actionSuggestions.length === 0) {
|
|
6536
|
+
return `[Agent message]
|
|
6392
6537
|
${stringifyTranscriptValue({ show }, "")}`;
|
|
6538
|
+
}
|
|
6539
|
+
const lines = artifactIds.slice(0, 8).map(
|
|
6540
|
+
(artifactId) => artifactSummaryLine(artifactId, artifactsById?.[artifactId])
|
|
6541
|
+
);
|
|
6542
|
+
if (artifactIds.length > 8) {
|
|
6543
|
+
lines.push(`- ${artifactIds.length - 8} more artifacts omitted`);
|
|
6544
|
+
}
|
|
6545
|
+
if (actionSuggestions.length > 0) {
|
|
6546
|
+
if (artifactIds.length > 0) lines.push("[Agent suggested actions]");
|
|
6547
|
+
for (const suggestion of actionSuggestions.slice(0, 8)) {
|
|
6548
|
+
lines.push(
|
|
6549
|
+
`- ${suggestion.label}${suggestion.description ? `; ${suggestion.description}` : ""}`
|
|
6550
|
+
);
|
|
6551
|
+
}
|
|
6552
|
+
if (actionSuggestions.length > 8) {
|
|
6553
|
+
lines.push(`- ${actionSuggestions.length - 8} more suggestions omitted`);
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6556
|
+
const otherRefs = {
|
|
6557
|
+
entryPaths: show.entryPaths,
|
|
6558
|
+
listNames: show.listNames,
|
|
6559
|
+
variableNames: show.variableNames,
|
|
6560
|
+
fileIds: show.fileIds
|
|
6561
|
+
};
|
|
6562
|
+
const hasOtherRefs = Object.values(otherRefs).some(
|
|
6563
|
+
(value) => Array.isArray(value) && value.length > 0
|
|
6564
|
+
);
|
|
6565
|
+
const title = artifactIds.length > 0 ? "[Agent displayed session artifacts]" : "[Agent suggested actions]";
|
|
6566
|
+
return [
|
|
6567
|
+
title,
|
|
6568
|
+
...lines,
|
|
6569
|
+
hasOtherRefs ? `Other shown refs: ${stringifyTranscriptValue(otherRefs, "")}` : null
|
|
6570
|
+
].filter(Boolean).join("\n");
|
|
6393
6571
|
}
|
|
6394
|
-
function normalizeConversationMessage(raw) {
|
|
6572
|
+
function normalizeConversationMessage(raw, artifactsById) {
|
|
6395
6573
|
const record = asRecord3(raw);
|
|
6396
6574
|
if (!record) return null;
|
|
6397
6575
|
const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
|
|
@@ -6403,6 +6581,12 @@ function normalizeConversationMessage(raw) {
|
|
|
6403
6581
|
const id = asString(record.id) || crypto.randomUUID();
|
|
6404
6582
|
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
6405
6583
|
if (!content && !show) return null;
|
|
6584
|
+
const artifactHistory = buildArtifactHistory(show, artifactsById);
|
|
6585
|
+
const historyContent = role === "assistant" ? content && artifactHistory ? `[Assistant reply]
|
|
6586
|
+
${content}
|
|
6587
|
+
|
|
6588
|
+
${artifactHistory}` : content ? `[Assistant reply]
|
|
6589
|
+
${content}` : artifactHistory : void 0;
|
|
6406
6590
|
return {
|
|
6407
6591
|
id,
|
|
6408
6592
|
role,
|
|
@@ -6411,8 +6595,7 @@ function normalizeConversationMessage(raw) {
|
|
|
6411
6595
|
jobId: asString(record.jobId),
|
|
6412
6596
|
promptId: asString(record.promptId),
|
|
6413
6597
|
show,
|
|
6414
|
-
historyContent
|
|
6415
|
-
${content}` : buildArtifactHistory(show) : void 0,
|
|
6598
|
+
historyContent,
|
|
6416
6599
|
source: "conversation"
|
|
6417
6600
|
};
|
|
6418
6601
|
}
|
|
@@ -6455,7 +6638,7 @@ ${assistantContent}`,
|
|
|
6455
6638
|
return entries;
|
|
6456
6639
|
});
|
|
6457
6640
|
}
|
|
6458
|
-
function normalizeAgentMessageEntries(jobId, rawMessages) {
|
|
6641
|
+
function normalizeAgentMessageEntries(jobId, rawMessages, artifactsById) {
|
|
6459
6642
|
return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
6460
6643
|
(left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
|
|
6461
6644
|
).flatMap((message) => {
|
|
@@ -6486,14 +6669,14 @@ ${reply}`,
|
|
|
6486
6669
|
timestamp,
|
|
6487
6670
|
jobId,
|
|
6488
6671
|
show,
|
|
6489
|
-
historyContent: buildArtifactHistory(show),
|
|
6672
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6490
6673
|
source: "job_agent_message"
|
|
6491
6674
|
});
|
|
6492
6675
|
}
|
|
6493
6676
|
return entries;
|
|
6494
6677
|
});
|
|
6495
6678
|
}
|
|
6496
|
-
function buildJobFallbackEntries(jobId, job, sessionHeap) {
|
|
6679
|
+
function buildJobFallbackEntries(jobId, job, sessionHeap, artifactsById) {
|
|
6497
6680
|
const timestamp = asNumber(job.finishedAt) || asNumber(job.startedAt) || asNumber(job.submittedAt) || 0;
|
|
6498
6681
|
const resultPreview = stringifyTranscriptValue(
|
|
6499
6682
|
job.result,
|
|
@@ -6531,7 +6714,7 @@ ${responseText}`,
|
|
|
6531
6714
|
timestamp,
|
|
6532
6715
|
jobId,
|
|
6533
6716
|
show,
|
|
6534
|
-
historyContent: buildArtifactHistory(show),
|
|
6717
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6535
6718
|
source: "job_result"
|
|
6536
6719
|
});
|
|
6537
6720
|
}
|
|
@@ -6585,10 +6768,11 @@ function buildJobCodeEntry(jobId, job) {
|
|
|
6585
6768
|
function buildSessionTranscript(input) {
|
|
6586
6769
|
const liveDoc = input.liveDoc || null;
|
|
6587
6770
|
const sessionHeap = input.sessionHeap || EMPTY_HEAP;
|
|
6771
|
+
const artifactsById = artifactRecordsById(liveDoc);
|
|
6588
6772
|
const transcript = [];
|
|
6589
6773
|
const conversationMessages = asArray(
|
|
6590
6774
|
asRecord3(liveDoc?.conversation)?.messages
|
|
6591
|
-
).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
|
|
6775
|
+
).map((message) => normalizeConversationMessage(message, artifactsById)).filter((message) => Boolean(message));
|
|
6592
6776
|
const conversationPromptIds = new Set(
|
|
6593
6777
|
conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
|
|
6594
6778
|
);
|
|
@@ -6615,7 +6799,8 @@ function buildSessionTranscript(input) {
|
|
|
6615
6799
|
if (!assistantConversationJobIds.has(jobId)) {
|
|
6616
6800
|
const agentEntries = normalizeAgentMessageEntries(
|
|
6617
6801
|
jobId,
|
|
6618
|
-
job.agentMessages
|
|
6802
|
+
job.agentMessages,
|
|
6803
|
+
artifactsById
|
|
6619
6804
|
);
|
|
6620
6805
|
if (agentEntries.length > 0) {
|
|
6621
6806
|
transcript.push(...agentEntries);
|
|
@@ -6624,7 +6809,8 @@ function buildSessionTranscript(input) {
|
|
|
6624
6809
|
...buildJobFallbackEntries(
|
|
6625
6810
|
jobId,
|
|
6626
6811
|
job,
|
|
6627
|
-
sessionHeap
|
|
6812
|
+
sessionHeap,
|
|
6813
|
+
artifactsById
|
|
6628
6814
|
)
|
|
6629
6815
|
);
|
|
6630
6816
|
}
|
|
@@ -10790,16 +10976,107 @@ var StateMachineStateSchema = external_exports.union([
|
|
|
10790
10976
|
external_exports.string(),
|
|
10791
10977
|
external_exports.object({
|
|
10792
10978
|
name: external_exports.string().min(1),
|
|
10979
|
+
label: external_exports.string().optional(),
|
|
10980
|
+
description: external_exports.string().optional(),
|
|
10793
10981
|
isFinal: external_exports.boolean().optional()
|
|
10794
10982
|
}).strict()
|
|
10795
10983
|
]);
|
|
10984
|
+
var StateTransitionInputBindingSchema = external_exports.lazy(
|
|
10985
|
+
() => external_exports.union([
|
|
10986
|
+
external_exports.null(),
|
|
10987
|
+
external_exports.string(),
|
|
10988
|
+
external_exports.number(),
|
|
10989
|
+
external_exports.boolean(),
|
|
10990
|
+
external_exports.array(StateTransitionInputBindingSchema),
|
|
10991
|
+
external_exports.object({
|
|
10992
|
+
const: external_exports.unknown()
|
|
10993
|
+
}).strict(),
|
|
10994
|
+
external_exports.object({
|
|
10995
|
+
from: external_exports.literal("object"),
|
|
10996
|
+
path: external_exports.string().min(1),
|
|
10997
|
+
editable: external_exports.boolean().optional()
|
|
10998
|
+
}).strict(),
|
|
10999
|
+
external_exports.object({
|
|
11000
|
+
from: external_exports.literal("field"),
|
|
11001
|
+
name: external_exports.string().min(1),
|
|
11002
|
+
editable: external_exports.boolean().optional()
|
|
11003
|
+
}).strict(),
|
|
11004
|
+
external_exports.object({
|
|
11005
|
+
from: external_exports.literal("relationship"),
|
|
11006
|
+
name: external_exports.string().min(1),
|
|
11007
|
+
path: external_exports.string().min(1).optional(),
|
|
11008
|
+
many: external_exports.boolean().optional(),
|
|
11009
|
+
editable: external_exports.boolean().optional()
|
|
11010
|
+
}).strict(),
|
|
11011
|
+
external_exports.object({
|
|
11012
|
+
from: external_exports.literal("session"),
|
|
11013
|
+
path: external_exports.string().min(1),
|
|
11014
|
+
editable: external_exports.boolean().optional()
|
|
11015
|
+
}).strict(),
|
|
11016
|
+
external_exports.object({
|
|
11017
|
+
from: external_exports.literal("actor"),
|
|
11018
|
+
path: external_exports.string().min(1),
|
|
11019
|
+
editable: external_exports.boolean().optional()
|
|
11020
|
+
}).strict(),
|
|
11021
|
+
external_exports.record(external_exports.string(), StateTransitionInputBindingSchema)
|
|
11022
|
+
])
|
|
11023
|
+
);
|
|
11024
|
+
var StateTransitionActionSchema = external_exports.object({
|
|
11025
|
+
effect: external_exports.string().min(1),
|
|
11026
|
+
input: external_exports.record(external_exports.string(), StateTransitionInputBindingSchema).optional()
|
|
11027
|
+
}).strict();
|
|
11028
|
+
var StateTransitionAssigneeSchema = external_exports.object({
|
|
11029
|
+
kind: external_exports.string().min(1),
|
|
11030
|
+
from: StateTransitionInputBindingSchema.optional(),
|
|
11031
|
+
role: external_exports.string().optional(),
|
|
11032
|
+
label: external_exports.string().optional()
|
|
11033
|
+
}).strict();
|
|
11034
|
+
var StateTransitionRelatedStateRequirementSchema = external_exports.object({
|
|
11035
|
+
relationship: external_exports.string().min(1),
|
|
11036
|
+
machine: external_exports.string().min(1),
|
|
11037
|
+
state: external_exports.string().min(1),
|
|
11038
|
+
className: external_exports.string().min(1).optional(),
|
|
11039
|
+
label: external_exports.string().optional(),
|
|
11040
|
+
mode: external_exports.enum(["every", "some", "any"]).optional()
|
|
11041
|
+
}).strict();
|
|
11042
|
+
var StateTransitionRequirementsSchema = external_exports.object({
|
|
11043
|
+
fields: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11044
|
+
relationships: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11045
|
+
relatedStates: external_exports.array(StateTransitionRelatedStateRequirementSchema).optional()
|
|
11046
|
+
}).strict();
|
|
11047
|
+
var StateTransitionPermissionSchema = external_exports.union([
|
|
11048
|
+
external_exports.string().min(1),
|
|
11049
|
+
external_exports.object({
|
|
11050
|
+
profile: external_exports.string().min(1).optional(),
|
|
11051
|
+
profileId: external_exports.string().min(1).optional(),
|
|
11052
|
+
label: external_exports.string().optional(),
|
|
11053
|
+
reason: external_exports.string().optional()
|
|
11054
|
+
}).strict()
|
|
11055
|
+
]);
|
|
11056
|
+
var StateTransitionExpectedOutcomeSchema = external_exports.union([
|
|
11057
|
+
external_exports.string().min(1),
|
|
11058
|
+
external_exports.object({
|
|
11059
|
+
machine: external_exports.string().min(1).optional(),
|
|
11060
|
+
state: external_exports.string().min(1),
|
|
11061
|
+
summary: external_exports.string().optional()
|
|
11062
|
+
}).strict()
|
|
11063
|
+
]);
|
|
10796
11064
|
var StateMachineTransitionSchema = external_exports.object({
|
|
10797
11065
|
name: external_exports.string().min(1),
|
|
10798
11066
|
from: external_exports.string().min(1),
|
|
10799
|
-
to: external_exports.string().min(1)
|
|
11067
|
+
to: external_exports.string().min(1),
|
|
11068
|
+
label: external_exports.string().optional(),
|
|
11069
|
+
description: external_exports.string().optional(),
|
|
11070
|
+
action: StateTransitionActionSchema.optional(),
|
|
11071
|
+
assignee: StateTransitionAssigneeSchema.optional(),
|
|
11072
|
+
requirements: StateTransitionRequirementsSchema.optional(),
|
|
11073
|
+
permission: StateTransitionPermissionSchema.optional(),
|
|
11074
|
+
risk: external_exports.enum(["low", "medium", "high"]).optional(),
|
|
11075
|
+
expectedOutcome: StateTransitionExpectedOutcomeSchema.optional()
|
|
10800
11076
|
}).strict();
|
|
10801
11077
|
external_exports.object({
|
|
10802
11078
|
name: external_exports.string().min(1),
|
|
11079
|
+
stateField: external_exports.string().min(1).optional(),
|
|
10803
11080
|
entryState: external_exports.string().min(1),
|
|
10804
11081
|
states: external_exports.array(StateMachineStateSchema).min(1),
|
|
10805
11082
|
transitions: external_exports.array(StateMachineTransitionSchema),
|
|
@@ -10866,6 +11143,16 @@ var PoliciesSchema = external_exports.object({
|
|
|
10866
11143
|
confirmWhen: external_exports.array(PolicyRuleSchema).optional(),
|
|
10867
11144
|
denyWhen: external_exports.array(PolicyRuleSchema).optional()
|
|
10868
11145
|
}).strict();
|
|
11146
|
+
var CreatesSchema = external_exports.union([
|
|
11147
|
+
external_exports.string().min(1),
|
|
11148
|
+
external_exports.object({
|
|
11149
|
+
className: external_exports.string().min(1),
|
|
11150
|
+
idPath: external_exports.string().min(1).optional(),
|
|
11151
|
+
pathPath: external_exports.string().min(1).optional(),
|
|
11152
|
+
statePath: external_exports.string().min(1).optional(),
|
|
11153
|
+
classStateHandle: external_exports.boolean().optional()
|
|
11154
|
+
}).strict()
|
|
11155
|
+
]);
|
|
10869
11156
|
external_exports.object({
|
|
10870
11157
|
postCondition: external_exports.union([
|
|
10871
11158
|
external_exports.string(),
|
|
@@ -10896,6 +11183,7 @@ external_exports.object({
|
|
|
10896
11183
|
mode: external_exports.string().optional()
|
|
10897
11184
|
}).strict()
|
|
10898
11185
|
]).optional(),
|
|
11186
|
+
creates: CreatesSchema.optional(),
|
|
10899
11187
|
access: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10900
11188
|
effectKind: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10901
11189
|
sideEffect: external_exports.enum(["read", "write", "ui", "readonly", "read_only"]).optional(),
|
|
@@ -11123,9 +11411,10 @@ function mergeMethodSummaryPatch(target, patch) {
|
|
|
11123
11411
|
if (patch.metamodels !== void 0) target.metamodels = patch.metamodels;
|
|
11124
11412
|
if (patch.effectBehaviors !== void 0)
|
|
11125
11413
|
target.effectBehaviors = patch.effectBehaviors;
|
|
11414
|
+
if (patch.creates !== void 0) target.creates = patch.creates;
|
|
11126
11415
|
if (patch.static !== void 0) target.static = patch.static;
|
|
11127
11416
|
}
|
|
11128
|
-
function
|
|
11417
|
+
function toPascalCase2(value) {
|
|
11129
11418
|
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
11130
11419
|
}
|
|
11131
11420
|
function normalizeNotesInput(input) {
|
|
@@ -11183,29 +11472,60 @@ function normalizeEffectBehaviorSummary(metamodels) {
|
|
|
11183
11472
|
}
|
|
11184
11473
|
return Object.keys(result).length > 0 ? result : null;
|
|
11185
11474
|
}
|
|
11186
|
-
function
|
|
11187
|
-
if (!
|
|
11188
|
-
|
|
11475
|
+
function normalizeCreationSummary(metamodels) {
|
|
11476
|
+
if (!isObject(metamodels)) return null;
|
|
11477
|
+
let raw = metamodels.creates;
|
|
11478
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11479
|
+
const trimmed = raw.trim();
|
|
11480
|
+
if (trimmed.startsWith("{") || trimmed.startsWith('"')) {
|
|
11481
|
+
try {
|
|
11482
|
+
raw = JSON.parse(trimmed);
|
|
11483
|
+
} catch {
|
|
11484
|
+
return { className: trimmed };
|
|
11485
|
+
}
|
|
11486
|
+
} else {
|
|
11487
|
+
return { className: trimmed };
|
|
11488
|
+
}
|
|
11189
11489
|
}
|
|
11490
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11491
|
+
return { className: raw.trim() };
|
|
11492
|
+
}
|
|
11493
|
+
if (!isObject(raw)) return null;
|
|
11494
|
+
const className = typeof raw.className === "string" && raw.className.trim() ? raw.className.trim() : "";
|
|
11495
|
+
if (!className) return null;
|
|
11496
|
+
return {
|
|
11497
|
+
className,
|
|
11498
|
+
...typeof raw.idPath === "string" && raw.idPath.trim() ? { idPath: raw.idPath.trim() } : {},
|
|
11499
|
+
...typeof raw.pathPath === "string" && raw.pathPath.trim() ? { pathPath: raw.pathPath.trim() } : {},
|
|
11500
|
+
...typeof raw.statePath === "string" && raw.statePath.trim() ? { statePath: raw.statePath.trim() } : {},
|
|
11501
|
+
...typeof raw.classStateHandle === "boolean" ? { classStateHandle: raw.classStateHandle } : {}
|
|
11502
|
+
};
|
|
11503
|
+
}
|
|
11504
|
+
function buildEffectBehaviorDocs(effectBehaviors, creates) {
|
|
11190
11505
|
const docs = [];
|
|
11191
|
-
if (
|
|
11506
|
+
if (creates) {
|
|
11507
|
+
docs.push(
|
|
11508
|
+
`Creation method: creates ${creates.className}. The agent may use generated class-level new-record action methods for this class.`
|
|
11509
|
+
);
|
|
11510
|
+
}
|
|
11511
|
+
if (effectBehaviors?.approvalRequired?.required) {
|
|
11192
11512
|
docs.push(
|
|
11193
11513
|
effectBehaviors.approvalRequired.reason ? `Approval required: ${effectBehaviors.approvalRequired.reason}.` : "Approval required before execution."
|
|
11194
11514
|
);
|
|
11195
11515
|
}
|
|
11196
|
-
if (effectBehaviors
|
|
11516
|
+
if (effectBehaviors?.postCondition) {
|
|
11197
11517
|
docs.push(`Post-condition: ${effectBehaviors.postCondition.condition}.`);
|
|
11198
11518
|
if (effectBehaviors.postCondition.description) {
|
|
11199
11519
|
docs.push(effectBehaviors.postCondition.description);
|
|
11200
11520
|
}
|
|
11201
11521
|
}
|
|
11202
|
-
if (effectBehaviors
|
|
11522
|
+
if (effectBehaviors?.dryRun?.enabled) {
|
|
11203
11523
|
docs.push("Supports dry run.");
|
|
11204
11524
|
if (effectBehaviors.dryRun.description) {
|
|
11205
11525
|
docs.push(effectBehaviors.dryRun.description);
|
|
11206
11526
|
}
|
|
11207
11527
|
}
|
|
11208
|
-
if (effectBehaviors
|
|
11528
|
+
if (effectBehaviors?.reverse) {
|
|
11209
11529
|
if (effectBehaviors.reverse.handler) {
|
|
11210
11530
|
docs.push(`Reverse handler: ${effectBehaviors.reverse.handler}.`);
|
|
11211
11531
|
} else {
|
|
@@ -11264,13 +11584,21 @@ function buildEffectBehaviorMutations(toolPath, spec) {
|
|
|
11264
11584
|
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { set_approval_required(${args}) { kind } } }`
|
|
11265
11585
|
});
|
|
11266
11586
|
}
|
|
11587
|
+
if (spec.creates !== void 0) {
|
|
11588
|
+
mutations.push({
|
|
11589
|
+
label: `set creates on ${toolPath}`,
|
|
11590
|
+
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "creates", label: "creates") { set_string_value(value: ${JSON.stringify(
|
|
11591
|
+
JSON.stringify(spec.creates)
|
|
11592
|
+
)}) { done } } } }`
|
|
11593
|
+
});
|
|
11594
|
+
}
|
|
11267
11595
|
return mutations;
|
|
11268
11596
|
}
|
|
11269
11597
|
function readMethodEffectBehaviors(rawMethod) {
|
|
11598
|
+
const metamodels = isObject(rawMethod.metamodels) ? rawMethod.metamodels : null;
|
|
11270
11599
|
return {
|
|
11271
|
-
effectBehaviors: normalizeEffectBehaviorSummary(
|
|
11272
|
-
|
|
11273
|
-
)
|
|
11600
|
+
effectBehaviors: normalizeEffectBehaviorSummary(metamodels),
|
|
11601
|
+
creates: normalizeCreationSummary(metamodels)
|
|
11274
11602
|
};
|
|
11275
11603
|
}
|
|
11276
11604
|
var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
@@ -11292,6 +11620,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11292
11620
|
{
|
|
11293
11621
|
key: "approvalRequired",
|
|
11294
11622
|
description: "Boolean or `{ required, reason, mode }`."
|
|
11623
|
+
},
|
|
11624
|
+
{
|
|
11625
|
+
key: "creates",
|
|
11626
|
+
description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, classStateHandle }`.'
|
|
11295
11627
|
}
|
|
11296
11628
|
]
|
|
11297
11629
|
},
|
|
@@ -11411,7 +11743,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11411
11743
|
...methodIR,
|
|
11412
11744
|
docs: [
|
|
11413
11745
|
...methodIR.docs,
|
|
11414
|
-
...buildEffectBehaviorDocs(
|
|
11746
|
+
...buildEffectBehaviorDocs(
|
|
11747
|
+
methodSummary.effectBehaviors,
|
|
11748
|
+
methodSummary.creates
|
|
11749
|
+
)
|
|
11415
11750
|
]
|
|
11416
11751
|
};
|
|
11417
11752
|
}
|
|
@@ -11652,15 +11987,50 @@ function toRecordSearchResult(className, node) {
|
|
|
11652
11987
|
return [];
|
|
11653
11988
|
}
|
|
11654
11989
|
) : [];
|
|
11990
|
+
const graphPathId = extractRecordIdFromGraphPath(path, className);
|
|
11991
|
+
const realIdField = fields.find(
|
|
11992
|
+
(field) => normalizeGraphPathSegment(field.name) === "real_id" && typeof field.value === "string" && field.value.trim()
|
|
11993
|
+
);
|
|
11994
|
+
const id = typeof realIdField?.value === "string" ? realIdField.value.trim() : graphPathId;
|
|
11995
|
+
const rawLabel = typeof node.label === "string" && node.label.trim() ? node.label : "";
|
|
11996
|
+
if (fields.length === 0 && rawLabel && isPlaceholderRecordLabel(rawLabel, graphPathId, path)) {
|
|
11997
|
+
return null;
|
|
11998
|
+
}
|
|
11999
|
+
const fallbackLabel = displayLabelFromFields(fields);
|
|
12000
|
+
const label = rawLabel && !isPlaceholderRecordLabel(rawLabel, id, path) ? rawLabel : fallbackLabel || rawLabel || id;
|
|
11655
12001
|
return {
|
|
11656
12002
|
path,
|
|
11657
12003
|
className,
|
|
11658
|
-
id
|
|
11659
|
-
label
|
|
12004
|
+
id,
|
|
12005
|
+
label,
|
|
11660
12006
|
description: typeof node.description === "string" && node.description.trim() ? node.description : null,
|
|
11661
12007
|
fields
|
|
11662
12008
|
};
|
|
11663
12009
|
}
|
|
12010
|
+
function isPlaceholderRecordLabel(label, id, path) {
|
|
12011
|
+
const normalizedLabel = normalizeGraphPathSegment(label);
|
|
12012
|
+
return normalizedLabel === normalizeGraphPathSegment(id) || normalizedLabel === normalizeGraphPathSegment(path);
|
|
12013
|
+
}
|
|
12014
|
+
function displayLabelFromFields(fields) {
|
|
12015
|
+
const preferredFieldNames = [
|
|
12016
|
+
"name",
|
|
12017
|
+
"title",
|
|
12018
|
+
"label",
|
|
12019
|
+
"display_name",
|
|
12020
|
+
"file_name",
|
|
12021
|
+
"number",
|
|
12022
|
+
"code"
|
|
12023
|
+
];
|
|
12024
|
+
for (const preferred of preferredFieldNames) {
|
|
12025
|
+
const match = fields.find(
|
|
12026
|
+
(field) => normalizeGraphPathSegment(field.name) === preferred && typeof field.value === "string" && field.value.trim()
|
|
12027
|
+
);
|
|
12028
|
+
if (typeof match?.value === "string") {
|
|
12029
|
+
return match.value.trim();
|
|
12030
|
+
}
|
|
12031
|
+
}
|
|
12032
|
+
return null;
|
|
12033
|
+
}
|
|
11664
12034
|
function normalizeRecordSearchText(value) {
|
|
11665
12035
|
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
|
|
11666
12036
|
}
|
|
@@ -12560,15 +12930,47 @@ var searchableMetamodelPackage = defineMetamodelPackage({
|
|
|
12560
12930
|
|
|
12561
12931
|
// ../metamodel-state-machine/src/index.ts
|
|
12562
12932
|
function normalizeStateMachines(values) {
|
|
12933
|
+
const parseJsonRecord = (value) => {
|
|
12934
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
12935
|
+
return value;
|
|
12936
|
+
}
|
|
12937
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
12938
|
+
try {
|
|
12939
|
+
const parsed = JSON.parse(value);
|
|
12940
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
12941
|
+
} catch {
|
|
12942
|
+
return null;
|
|
12943
|
+
}
|
|
12944
|
+
};
|
|
12945
|
+
const parseJsonValue = (value) => {
|
|
12946
|
+
if (value === null || typeof value === "undefined") return null;
|
|
12947
|
+
if (typeof value !== "string") return value;
|
|
12948
|
+
if (!value.trim()) return null;
|
|
12949
|
+
try {
|
|
12950
|
+
return JSON.parse(value);
|
|
12951
|
+
} catch {
|
|
12952
|
+
return value;
|
|
12953
|
+
}
|
|
12954
|
+
};
|
|
12563
12955
|
return (values || []).map((machine) => {
|
|
12564
12956
|
const states = (machine?.states || []).map((state) => ({
|
|
12565
12957
|
name: String(state?.name || ""),
|
|
12566
|
-
|
|
12958
|
+
label: typeof state?.label === "string" ? state.label : null,
|
|
12959
|
+
description: typeof state?.description === "string" ? state.description : null,
|
|
12960
|
+
isFinal: Boolean(state?.is_final ?? state?.isFinal)
|
|
12567
12961
|
})).filter((state) => state.name.length > 0);
|
|
12568
12962
|
const transitions = (machine?.transitions || []).map((transition) => ({
|
|
12569
12963
|
name: String(transition?.name || ""),
|
|
12570
12964
|
from: String(transition?.from?.name || ""),
|
|
12571
|
-
to: String(transition?.to?.name || "")
|
|
12965
|
+
to: String(transition?.to?.name || ""),
|
|
12966
|
+
label: typeof transition?.label === "string" ? transition.label : null,
|
|
12967
|
+
description: typeof transition?.description === "string" ? transition.description : null,
|
|
12968
|
+
action: parseJsonRecord(transition?.action) || parseJsonRecord(transition?.action_json),
|
|
12969
|
+
assignee: parseJsonRecord(transition?.assignee) || parseJsonRecord(transition?.assignee_json),
|
|
12970
|
+
requirements: parseJsonRecord(transition?.requirements) || parseJsonRecord(transition?.requirements_json),
|
|
12971
|
+
permission: parseJsonValue(transition?.permission) ?? parseJsonValue(transition?.permission_json),
|
|
12972
|
+
risk: transition?.risk === "low" || transition?.risk === "medium" || transition?.risk === "high" ? transition.risk : null,
|
|
12973
|
+
expectedOutcome: parseJsonValue(transition?.expectedOutcome) ?? parseJsonValue(transition?.expected_outcome_json)
|
|
12572
12974
|
})).filter(
|
|
12573
12975
|
(transition) => transition.name.length > 0 && transition.from.length > 0 && transition.to.length > 0
|
|
12574
12976
|
);
|
|
@@ -12582,7 +12984,7 @@ function normalizeStateMachines(values) {
|
|
|
12582
12984
|
}).filter((machine) => machine.name.length > 0);
|
|
12583
12985
|
}
|
|
12584
12986
|
function stateTypeName(className, machineName) {
|
|
12585
|
-
return `${
|
|
12987
|
+
return `${toPascalCase2(className)}${toPascalCase2(machineName)}`;
|
|
12586
12988
|
}
|
|
12587
12989
|
function transitionTypeName(className, machineName) {
|
|
12588
12990
|
return `${stateTypeName(className, machineName)}Transition`;
|
|
@@ -12590,6 +12992,15 @@ function transitionTypeName(className, machineName) {
|
|
|
12590
12992
|
function pathTypeName(className, machineName) {
|
|
12591
12993
|
return `${stateTypeName(className, machineName)}Path`;
|
|
12592
12994
|
}
|
|
12995
|
+
function methodToken(value) {
|
|
12996
|
+
const token = String(value || "").trim().replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
12997
|
+
return token || "state";
|
|
12998
|
+
}
|
|
12999
|
+
function transitionActionsForMachine(machine) {
|
|
13000
|
+
return Object.fromEntries(
|
|
13001
|
+
(machine.transitions || []).filter((transition) => transition.action?.effect).map((transition) => [transition.name, transition.action])
|
|
13002
|
+
);
|
|
13003
|
+
}
|
|
12593
13004
|
function normalizeStateDefinitions(machine) {
|
|
12594
13005
|
const finalStates = new Set(machine.finalStates || []);
|
|
12595
13006
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -12603,6 +13014,8 @@ function normalizeStateDefinitions(machine) {
|
|
|
12603
13014
|
}
|
|
12604
13015
|
states.set(rawState.name, {
|
|
12605
13016
|
name: rawState.name,
|
|
13017
|
+
label: rawState.label,
|
|
13018
|
+
description: rawState.description,
|
|
12606
13019
|
isFinal: Boolean(rawState.isFinal) || finalStates.has(rawState.name)
|
|
12607
13020
|
});
|
|
12608
13021
|
}
|
|
@@ -12614,6 +13027,44 @@ function normalizeStateDefinitions(machine) {
|
|
|
12614
13027
|
}
|
|
12615
13028
|
return [...states.values()];
|
|
12616
13029
|
}
|
|
13030
|
+
function transitionMetadataGraphqlArgs(transition) {
|
|
13031
|
+
const args = [];
|
|
13032
|
+
if (typeof transition.label === "string") {
|
|
13033
|
+
args.push(`label: ${JSON.stringify(transition.label)}`);
|
|
13034
|
+
}
|
|
13035
|
+
if (typeof transition.description === "string") {
|
|
13036
|
+
args.push(`description: ${JSON.stringify(transition.description)}`);
|
|
13037
|
+
}
|
|
13038
|
+
if (transition.action) {
|
|
13039
|
+
args.push(
|
|
13040
|
+
`action_json: ${JSON.stringify(JSON.stringify(transition.action))}`
|
|
13041
|
+
);
|
|
13042
|
+
}
|
|
13043
|
+
if (transition.assignee) {
|
|
13044
|
+
args.push(
|
|
13045
|
+
`assignee_json: ${JSON.stringify(JSON.stringify(transition.assignee))}`
|
|
13046
|
+
);
|
|
13047
|
+
}
|
|
13048
|
+
if (transition.requirements) {
|
|
13049
|
+
args.push(
|
|
13050
|
+
`requirements_json: ${JSON.stringify(JSON.stringify(transition.requirements))}`
|
|
13051
|
+
);
|
|
13052
|
+
}
|
|
13053
|
+
if (transition.permission) {
|
|
13054
|
+
args.push(
|
|
13055
|
+
`permission_json: ${JSON.stringify(JSON.stringify(transition.permission))}`
|
|
13056
|
+
);
|
|
13057
|
+
}
|
|
13058
|
+
if (transition.risk) {
|
|
13059
|
+
args.push(`risk: ${JSON.stringify(transition.risk)}`);
|
|
13060
|
+
}
|
|
13061
|
+
if (transition.expectedOutcome) {
|
|
13062
|
+
args.push(
|
|
13063
|
+
`expected_outcome_json: ${JSON.stringify(JSON.stringify(transition.expectedOutcome))}`
|
|
13064
|
+
);
|
|
13065
|
+
}
|
|
13066
|
+
return args.length > 0 ? `, ${args.join(", ")}` : "";
|
|
13067
|
+
}
|
|
12617
13068
|
function buildStateMachineModelMutations(modelPath, machines) {
|
|
12618
13069
|
const mutations = [];
|
|
12619
13070
|
for (const machine of machines || []) {
|
|
@@ -12624,12 +13075,13 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12624
13075
|
)}, entry_state: ${JSON.stringify(machine.entryState)}) { name } } }`
|
|
12625
13076
|
});
|
|
12626
13077
|
for (const state of normalizeStateDefinitions(machine)) {
|
|
12627
|
-
if (state.name === machine.entryState && !state.isFinal)
|
|
13078
|
+
if (state.name === machine.entryState && !state.isFinal && !state.label && !state.description)
|
|
13079
|
+
continue;
|
|
12628
13080
|
mutations.push({
|
|
12629
13081
|
label: `add state ${state.name} on ${modelPath}.${machine.name}`,
|
|
12630
13082
|
query: `mutation { at(path: ${JSON.stringify(modelPath)}) { state_machine(name: ${JSON.stringify(
|
|
12631
13083
|
machine.name
|
|
12632
|
-
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}) { name } } } }`
|
|
13084
|
+
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}, label: ${JSON.stringify(state.label || null)}, description: ${JSON.stringify(state.description || null)}) { name } } } }`
|
|
12633
13085
|
});
|
|
12634
13086
|
}
|
|
12635
13087
|
for (const transition of machine.transitions || []) {
|
|
@@ -12641,7 +13093,7 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12641
13093
|
transition.name
|
|
12642
13094
|
)}, from: ${JSON.stringify(transition.from)}, to: ${JSON.stringify(
|
|
12643
13095
|
transition.to
|
|
12644
|
-
)}) { name } } } }`
|
|
13096
|
+
)}${transitionMetadataGraphqlArgs(transition)}) { name } } } }`
|
|
12645
13097
|
});
|
|
12646
13098
|
}
|
|
12647
13099
|
}
|
|
@@ -12668,7 +13120,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12668
13120
|
const transitionName = transitionTypeName(classSummary.name, machine.name);
|
|
12669
13121
|
pathTypeName(classSummary.name, machine.name);
|
|
12670
13122
|
const docsPrefix = `${classSummary.name}.${machine.name}`;
|
|
12671
|
-
|
|
13123
|
+
const methods = [
|
|
12672
13124
|
{
|
|
12673
13125
|
name: `get_${machine.name}`,
|
|
12674
13126
|
docs: [`Get the current ${docsPrefix} state.`],
|
|
@@ -12691,7 +13143,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12691
13143
|
],
|
|
12692
13144
|
static: false,
|
|
12693
13145
|
params: [{ name: "target", type: stateName }],
|
|
12694
|
-
returnType: `Promise<${
|
|
13146
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
12695
13147
|
runtime: {
|
|
12696
13148
|
kind: "state_machine",
|
|
12697
13149
|
machineName: machine.name,
|
|
@@ -12764,6 +13216,99 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12764
13216
|
}
|
|
12765
13217
|
}
|
|
12766
13218
|
];
|
|
13219
|
+
const creationMethods = (classSummary.methods || []).filter(
|
|
13220
|
+
(method) => method.static === true && Boolean(method.creates) && method.creates?.className === classSummary.name && typeof method.effectKey === "string" && method.effectKey.length > 0
|
|
13221
|
+
);
|
|
13222
|
+
for (const state of machine.states) {
|
|
13223
|
+
const stateNameValue = typeof state === "string" ? state : String(state?.name || "");
|
|
13224
|
+
if (!stateNameValue) continue;
|
|
13225
|
+
const token = methodToken(stateNameValue);
|
|
13226
|
+
methods.push(
|
|
13227
|
+
{
|
|
13228
|
+
name: `reach_${machine.name}_to_${token}`,
|
|
13229
|
+
docs: [`Reach ${docsPrefix} state ${stateNameValue}.`],
|
|
13230
|
+
static: false,
|
|
13231
|
+
params: [],
|
|
13232
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
13233
|
+
runtime: {
|
|
13234
|
+
kind: "state_machine",
|
|
13235
|
+
machineName: machine.name,
|
|
13236
|
+
className: classSummary.name,
|
|
13237
|
+
stateTypeName: stateName,
|
|
13238
|
+
transitionTypeName: transitionName,
|
|
13239
|
+
operation: "reach",
|
|
13240
|
+
targetState: stateNameValue,
|
|
13241
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13242
|
+
}
|
|
13243
|
+
},
|
|
13244
|
+
{
|
|
13245
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13246
|
+
docs: [
|
|
13247
|
+
`Prepare a reviewable artifact that can move ${docsPrefix} to ${stateNameValue}.`
|
|
13248
|
+
],
|
|
13249
|
+
static: false,
|
|
13250
|
+
params: [],
|
|
13251
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13252
|
+
runtime: {
|
|
13253
|
+
kind: "state_machine",
|
|
13254
|
+
machineName: machine.name,
|
|
13255
|
+
className: classSummary.name,
|
|
13256
|
+
stateTypeName: stateName,
|
|
13257
|
+
transitionTypeName: transitionName,
|
|
13258
|
+
operation: "prepare_reach",
|
|
13259
|
+
targetState: stateNameValue,
|
|
13260
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13261
|
+
}
|
|
13262
|
+
}
|
|
13263
|
+
);
|
|
13264
|
+
for (const creationMethod of creationMethods) {
|
|
13265
|
+
const creationRuntime = {
|
|
13266
|
+
kind: "state_machine",
|
|
13267
|
+
machineName: machine.name,
|
|
13268
|
+
className: classSummary.name,
|
|
13269
|
+
stateTypeName: stateName,
|
|
13270
|
+
transitionTypeName: transitionName,
|
|
13271
|
+
operation: "prepare_create_reach",
|
|
13272
|
+
targetState: stateNameValue,
|
|
13273
|
+
transitionActions: transitionActionsForMachine(machine),
|
|
13274
|
+
creation: {
|
|
13275
|
+
methodName: creationMethod.name,
|
|
13276
|
+
effectKey: creationMethod.effectKey || creationMethod.name,
|
|
13277
|
+
inputSchema: creationMethod.inputSchema,
|
|
13278
|
+
outputSchema: creationMethod.outputSchema,
|
|
13279
|
+
creates: creationMethod.creates
|
|
13280
|
+
}
|
|
13281
|
+
};
|
|
13282
|
+
const viaName = `prepare_${machine.name}_to_${token}_via_${methodToken(creationMethod.name)}`;
|
|
13283
|
+
methods.push({
|
|
13284
|
+
name: viaName,
|
|
13285
|
+
docs: [
|
|
13286
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name} through ${creationMethod.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13287
|
+
],
|
|
13288
|
+
static: true,
|
|
13289
|
+
params: [
|
|
13290
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13291
|
+
],
|
|
13292
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13293
|
+
runtime: creationRuntime
|
|
13294
|
+
});
|
|
13295
|
+
if (creationMethods.length === 1) {
|
|
13296
|
+
methods.push({
|
|
13297
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13298
|
+
docs: [
|
|
13299
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13300
|
+
],
|
|
13301
|
+
static: true,
|
|
13302
|
+
params: [
|
|
13303
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13304
|
+
],
|
|
13305
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13306
|
+
runtime: creationRuntime
|
|
13307
|
+
});
|
|
13308
|
+
}
|
|
13309
|
+
}
|
|
13310
|
+
}
|
|
13311
|
+
return methods;
|
|
12767
13312
|
}
|
|
12768
13313
|
function readStateMachineSummaries(rawClass) {
|
|
12769
13314
|
return {
|
|
@@ -12786,8 +13331,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12786
13331
|
type StateMachineMutation {
|
|
12787
13332
|
name: String!
|
|
12788
13333
|
state_machine: StateMachine!
|
|
12789
|
-
add_state(name: String!, is_final: Boolean): StateMachineMutation!
|
|
12790
|
-
add_transition(name: String!, from: String!, to: String
|
|
13334
|
+
add_state(name: String!, is_final: Boolean, label: String, description: String): StateMachineMutation!
|
|
13335
|
+
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!
|
|
12791
13336
|
activate_transition(name: String!): StateMachineMutation!
|
|
12792
13337
|
}
|
|
12793
13338
|
|
|
@@ -12804,6 +13349,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12804
13349
|
type StateMachineSnapshotMutation {
|
|
12805
13350
|
snapshot: StateMachineSnapshot!
|
|
12806
13351
|
activate_transition(name: String!): StateMachineSnapshotMutation!
|
|
13352
|
+
observe_state(state: String!, force: Boolean, source: String): StateMachineSnapshotMutation!
|
|
12807
13353
|
}
|
|
12808
13354
|
|
|
12809
13355
|
type StateMachine {
|
|
@@ -12823,6 +13369,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12823
13369
|
|
|
12824
13370
|
type StateMachineState {
|
|
12825
13371
|
name: String!
|
|
13372
|
+
label: String
|
|
13373
|
+
description: String
|
|
12826
13374
|
is_final: Boolean!
|
|
12827
13375
|
}
|
|
12828
13376
|
|
|
@@ -12830,6 +13378,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12830
13378
|
name: String!
|
|
12831
13379
|
from: StateMachineState!
|
|
12832
13380
|
to: StateMachineState!
|
|
13381
|
+
label: String
|
|
13382
|
+
description: String
|
|
13383
|
+
action_json: String
|
|
13384
|
+
assignee_json: String
|
|
13385
|
+
requirements_json: String
|
|
13386
|
+
permission_json: String
|
|
13387
|
+
risk: String
|
|
13388
|
+
expected_outcome_json: String
|
|
12833
13389
|
}
|
|
12834
13390
|
|
|
12835
13391
|
type StateMachinePath {
|
|
@@ -12882,23 +13438,47 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12882
13438
|
StateMachineMutation: {
|
|
12883
13439
|
name: (value) => value.name,
|
|
12884
13440
|
state_machine: async (value) => await run(value.target.state_machine(value.name)),
|
|
12885
|
-
add_state: async (value, { name, is_final }) => {
|
|
13441
|
+
add_state: async (value, { name, is_final, label, description }) => {
|
|
12886
13442
|
await run(
|
|
12887
13443
|
value.target.add_state_machine_state(
|
|
12888
13444
|
value.name,
|
|
12889
13445
|
name,
|
|
12890
|
-
is_final ?? false
|
|
13446
|
+
is_final ?? false,
|
|
13447
|
+
label,
|
|
13448
|
+
description
|
|
12891
13449
|
)
|
|
12892
13450
|
);
|
|
12893
13451
|
return value;
|
|
12894
13452
|
},
|
|
12895
|
-
add_transition: async (value, {
|
|
13453
|
+
add_transition: async (value, {
|
|
13454
|
+
name,
|
|
13455
|
+
from,
|
|
13456
|
+
to,
|
|
13457
|
+
label,
|
|
13458
|
+
description,
|
|
13459
|
+
action_json,
|
|
13460
|
+
assignee_json,
|
|
13461
|
+
requirements_json,
|
|
13462
|
+
permission_json,
|
|
13463
|
+
risk,
|
|
13464
|
+
expected_outcome_json
|
|
13465
|
+
}) => {
|
|
12896
13466
|
await run(
|
|
12897
13467
|
value.target.add_state_machine_transition(
|
|
12898
13468
|
value.name,
|
|
12899
13469
|
name,
|
|
12900
13470
|
from,
|
|
12901
|
-
to
|
|
13471
|
+
to,
|
|
13472
|
+
{
|
|
13473
|
+
label,
|
|
13474
|
+
description,
|
|
13475
|
+
actionJson: action_json,
|
|
13476
|
+
assigneeJson: assignee_json,
|
|
13477
|
+
requirementsJson: requirements_json,
|
|
13478
|
+
permissionJson: permission_json,
|
|
13479
|
+
risk,
|
|
13480
|
+
expectedOutcomeJson: expected_outcome_json
|
|
13481
|
+
}
|
|
12902
13482
|
)
|
|
12903
13483
|
);
|
|
12904
13484
|
return value;
|
|
@@ -12917,16 +13497,37 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12917
13497
|
value.target.activate_state_machine_transition(value.name, name)
|
|
12918
13498
|
);
|
|
12919
13499
|
return value;
|
|
13500
|
+
},
|
|
13501
|
+
observe_state: async (value, { state, force, source }) => {
|
|
13502
|
+
await run(
|
|
13503
|
+
value.target.observe_state_machine_state(
|
|
13504
|
+
value.name,
|
|
13505
|
+
state,
|
|
13506
|
+
force === true,
|
|
13507
|
+
source
|
|
13508
|
+
)
|
|
13509
|
+
);
|
|
13510
|
+
return value;
|
|
12920
13511
|
}
|
|
12921
13512
|
},
|
|
12922
13513
|
StateMachineState: {
|
|
12923
13514
|
name: (value) => value.name,
|
|
13515
|
+
label: (value) => value.label || null,
|
|
13516
|
+
description: (value) => value.description || null,
|
|
12924
13517
|
is_final: (value) => value.is_final
|
|
12925
13518
|
},
|
|
12926
13519
|
StateMachineTransition: {
|
|
12927
13520
|
name: (value) => value.name,
|
|
12928
13521
|
from: (value) => value.from_state || { name: value.from, is_final: false },
|
|
12929
|
-
to: (value) => value.to_state || { name: value.to, is_final: false }
|
|
13522
|
+
to: (value) => value.to_state || { name: value.to, is_final: false },
|
|
13523
|
+
label: (value) => value.label || null,
|
|
13524
|
+
description: (value) => value.description || null,
|
|
13525
|
+
action_json: (value) => value.action_json || null,
|
|
13526
|
+
assignee_json: (value) => value.assignee_json || null,
|
|
13527
|
+
requirements_json: (value) => value.requirements_json || null,
|
|
13528
|
+
permission_json: (value) => value.permission_json || null,
|
|
13529
|
+
risk: (value) => value.risk || null,
|
|
13530
|
+
expected_outcome_json: (value) => value.expected_outcome_json || null
|
|
12930
13531
|
},
|
|
12931
13532
|
StateMachinePath: {
|
|
12932
13533
|
states: (value) => value.states,
|
|
@@ -12993,6 +13594,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12993
13594
|
name
|
|
12994
13595
|
from { name }
|
|
12995
13596
|
to { name }
|
|
13597
|
+
label
|
|
13598
|
+
description
|
|
13599
|
+
action_json
|
|
13600
|
+
assignee_json
|
|
13601
|
+
requirements_json
|
|
13602
|
+
permission_json
|
|
13603
|
+
risk
|
|
13604
|
+
expected_outcome_json
|
|
12996
13605
|
}
|
|
12997
13606
|
}`
|
|
12998
13607
|
]
|
|
@@ -13024,6 +13633,104 @@ function describeRule(rule) {
|
|
|
13024
13633
|
return `${rule.operator} ${String(rule.booleanValue)}`;
|
|
13025
13634
|
return rule.operator;
|
|
13026
13635
|
}
|
|
13636
|
+
function valueAsString(value) {
|
|
13637
|
+
if (typeof value === "string") return value;
|
|
13638
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
13639
|
+
return String(value);
|
|
13640
|
+
}
|
|
13641
|
+
return "";
|
|
13642
|
+
}
|
|
13643
|
+
function valueAsNumber(value) {
|
|
13644
|
+
if (typeof value === "number") return value;
|
|
13645
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
13646
|
+
const parsed = Number(value);
|
|
13647
|
+
return Number.isFinite(parsed) ? parsed : NaN;
|
|
13648
|
+
}
|
|
13649
|
+
return NaN;
|
|
13650
|
+
}
|
|
13651
|
+
function ruleStringValue(rule) {
|
|
13652
|
+
return rule.stringValue ?? rule.string_value ?? "";
|
|
13653
|
+
}
|
|
13654
|
+
function ruleNumberValue(rule) {
|
|
13655
|
+
return rule.numberValue ?? rule.number_value;
|
|
13656
|
+
}
|
|
13657
|
+
function ruleBooleanValue(rule) {
|
|
13658
|
+
return rule.booleanValue ?? rule.boolean_value;
|
|
13659
|
+
}
|
|
13660
|
+
function evaluateValidationRule(value, rule) {
|
|
13661
|
+
const operator = typeof rule.operator === "string" ? rule.operator : "";
|
|
13662
|
+
const stringValue2 = ruleStringValue(rule);
|
|
13663
|
+
const numberValue = ruleNumberValue(rule);
|
|
13664
|
+
const booleanValue = ruleBooleanValue(rule);
|
|
13665
|
+
let passed = true;
|
|
13666
|
+
switch (operator) {
|
|
13667
|
+
case "eq":
|
|
13668
|
+
if (numberValue !== void 0) {
|
|
13669
|
+
passed = valueAsNumber(value) === numberValue;
|
|
13670
|
+
} else if (booleanValue !== void 0) {
|
|
13671
|
+
passed = value === booleanValue;
|
|
13672
|
+
} else {
|
|
13673
|
+
passed = valueAsString(value) === stringValue2;
|
|
13674
|
+
}
|
|
13675
|
+
break;
|
|
13676
|
+
case "neq":
|
|
13677
|
+
if (numberValue !== void 0) {
|
|
13678
|
+
passed = valueAsNumber(value) !== numberValue;
|
|
13679
|
+
} else if (booleanValue !== void 0) {
|
|
13680
|
+
passed = value !== booleanValue;
|
|
13681
|
+
} else {
|
|
13682
|
+
passed = valueAsString(value) !== stringValue2;
|
|
13683
|
+
}
|
|
13684
|
+
break;
|
|
13685
|
+
case "gt":
|
|
13686
|
+
passed = valueAsNumber(value) > (numberValue ?? NaN);
|
|
13687
|
+
break;
|
|
13688
|
+
case "gte":
|
|
13689
|
+
passed = valueAsNumber(value) >= (numberValue ?? NaN);
|
|
13690
|
+
break;
|
|
13691
|
+
case "lt":
|
|
13692
|
+
passed = valueAsNumber(value) < (numberValue ?? NaN);
|
|
13693
|
+
break;
|
|
13694
|
+
case "lte":
|
|
13695
|
+
passed = valueAsNumber(value) <= (numberValue ?? NaN);
|
|
13696
|
+
break;
|
|
13697
|
+
case "true":
|
|
13698
|
+
passed = value === true;
|
|
13699
|
+
break;
|
|
13700
|
+
case "false":
|
|
13701
|
+
passed = value === false;
|
|
13702
|
+
break;
|
|
13703
|
+
case "regex":
|
|
13704
|
+
try {
|
|
13705
|
+
passed = new RegExp(stringValue2).test(valueAsString(value));
|
|
13706
|
+
} catch {
|
|
13707
|
+
passed = false;
|
|
13708
|
+
}
|
|
13709
|
+
break;
|
|
13710
|
+
case "contains":
|
|
13711
|
+
passed = valueAsString(value).includes(stringValue2);
|
|
13712
|
+
break;
|
|
13713
|
+
case "not_contains":
|
|
13714
|
+
passed = !valueAsString(value).includes(stringValue2);
|
|
13715
|
+
break;
|
|
13716
|
+
case "starts_with":
|
|
13717
|
+
passed = valueAsString(value).startsWith(stringValue2);
|
|
13718
|
+
break;
|
|
13719
|
+
case "ends_with":
|
|
13720
|
+
passed = valueAsString(value).endsWith(stringValue2);
|
|
13721
|
+
break;
|
|
13722
|
+
default:
|
|
13723
|
+
passed = true;
|
|
13724
|
+
}
|
|
13725
|
+
return {
|
|
13726
|
+
passed,
|
|
13727
|
+
operator,
|
|
13728
|
+
message: rule.message ?? null
|
|
13729
|
+
};
|
|
13730
|
+
}
|
|
13731
|
+
function validationRuleFailureMessage(path, rule) {
|
|
13732
|
+
return rule.message || `${path} failed ${rule.operator} validation`;
|
|
13733
|
+
}
|
|
13027
13734
|
function normalizeRule(rule) {
|
|
13028
13735
|
const operator = typeof rule?.operator === "string" ? rule.operator : "";
|
|
13029
13736
|
if (operator.length === 0) return null;
|
|
@@ -13246,6 +13953,26 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
13246
13953
|
var BUILTIN_MODULES = {
|
|
13247
13954
|
standard_modules: STANDARD_MODULES_OPERATIONS
|
|
13248
13955
|
};
|
|
13956
|
+
function stateNameFromMethodName(methodName) {
|
|
13957
|
+
const raw = methodName.startsWith("to") ? methodName.slice(2) : methodName;
|
|
13958
|
+
return raw.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
13959
|
+
}
|
|
13960
|
+
function appendQueryOptions(searchParams, query) {
|
|
13961
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
13962
|
+
if (value === null || typeof value === "undefined" || value === "") {
|
|
13963
|
+
continue;
|
|
13964
|
+
}
|
|
13965
|
+
if (value instanceof Date) {
|
|
13966
|
+
searchParams.set(key, value.toISOString());
|
|
13967
|
+
continue;
|
|
13968
|
+
}
|
|
13969
|
+
if (Array.isArray(value)) {
|
|
13970
|
+
if (value.length > 0) searchParams.set(key, value.join(","));
|
|
13971
|
+
continue;
|
|
13972
|
+
}
|
|
13973
|
+
searchParams.set(key, String(value));
|
|
13974
|
+
}
|
|
13975
|
+
}
|
|
13249
13976
|
var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
|
|
13250
13977
|
var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
|
|
13251
13978
|
var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
|
|
@@ -13276,8 +14003,20 @@ function bodyInitFromSessionFileUpload(body) {
|
|
|
13276
14003
|
return body;
|
|
13277
14004
|
}
|
|
13278
14005
|
var EFFECT_CATALOG_SYNC_TIMEOUT_MS = 12e4;
|
|
14006
|
+
var EFFECT_CATALOG_SYNC_BATCH_SIZE = 20;
|
|
13279
14007
|
var EFFECT_CATALOG_SYNC_RETRY_COUNT = 3;
|
|
13280
14008
|
var EFFECT_CATALOG_SYNC_RETRY_DELAY_MS = 1e3;
|
|
14009
|
+
function chunkItems(items, batchSize) {
|
|
14010
|
+
const chunks = [];
|
|
14011
|
+
for (let offset = 0; offset < items.length; offset += batchSize) {
|
|
14012
|
+
chunks.push(items.slice(offset, offset + batchSize));
|
|
14013
|
+
}
|
|
14014
|
+
return chunks;
|
|
14015
|
+
}
|
|
14016
|
+
function isUnsupportedEffectCatalogMutation(error) {
|
|
14017
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14018
|
+
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");
|
|
14019
|
+
}
|
|
13281
14020
|
function planRecordObjectsChunks(records, batchSize) {
|
|
13282
14021
|
const total = records.length;
|
|
13283
14022
|
const size = Math.max(1, Math.min(batchSize, total));
|
|
@@ -13289,6 +14028,23 @@ function planRecordObjectsChunks(records, batchSize) {
|
|
|
13289
14028
|
}
|
|
13290
14029
|
return plans;
|
|
13291
14030
|
}
|
|
14031
|
+
function preserveRecordObjectRealId(record) {
|
|
14032
|
+
const realId = record.id.trim();
|
|
14033
|
+
if (!realId) {
|
|
14034
|
+
return record;
|
|
14035
|
+
}
|
|
14036
|
+
const fields = record.fields || {};
|
|
14037
|
+
if (typeof fields.real_id === "string" && fields.real_id.trim()) {
|
|
14038
|
+
return record;
|
|
14039
|
+
}
|
|
14040
|
+
return {
|
|
14041
|
+
...record,
|
|
14042
|
+
fields: {
|
|
14043
|
+
...fields,
|
|
14044
|
+
real_id: realId
|
|
14045
|
+
}
|
|
14046
|
+
};
|
|
14047
|
+
}
|
|
13292
14048
|
function computeEffectKey2(effect) {
|
|
13293
14049
|
const attachedClass = effect.className?.trim();
|
|
13294
14050
|
if (!attachedClass) {
|
|
@@ -13526,11 +14282,105 @@ var Environment = class _Environment {
|
|
|
13526
14282
|
getAwaitingCount: async () => this.getAwaitingRecordCount()
|
|
13527
14283
|
};
|
|
13528
14284
|
}
|
|
14285
|
+
/**
|
|
14286
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14287
|
+
* own the customer application's state machine.
|
|
14288
|
+
*/
|
|
14289
|
+
async recordState(input) {
|
|
14290
|
+
const { machine, state, ...target } = input;
|
|
14291
|
+
if (!machine.trim()) {
|
|
14292
|
+
throw new Error("State update requires a machine name");
|
|
14293
|
+
}
|
|
14294
|
+
if (!state.trim()) {
|
|
14295
|
+
throw new Error("State update requires a state");
|
|
14296
|
+
}
|
|
14297
|
+
return this.recordObject({
|
|
14298
|
+
className: target.className,
|
|
14299
|
+
id: target.id,
|
|
14300
|
+
...target.label ? { label: target.label } : {},
|
|
14301
|
+
...target.fields ? { fields: target.fields } : {},
|
|
14302
|
+
...target.relationships ? { relationships: target.relationships } : {},
|
|
14303
|
+
states: {
|
|
14304
|
+
[machine.trim()]: {
|
|
14305
|
+
state: state.trim(),
|
|
14306
|
+
...target.source ? { source: target.source } : {},
|
|
14307
|
+
...target.cause ? { cause: target.cause } : {},
|
|
14308
|
+
...target.actorId ? { actorId: target.actorId } : {},
|
|
14309
|
+
...target.observedAt !== void 0 ? { observedAt: target.observedAt } : {},
|
|
14310
|
+
...target.force !== void 0 ? { force: target.force } : {},
|
|
14311
|
+
...target.metadata ? { metadata: target.metadata } : {}
|
|
14312
|
+
}
|
|
14313
|
+
}
|
|
14314
|
+
});
|
|
14315
|
+
}
|
|
14316
|
+
/**
|
|
14317
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14318
|
+
* own the customer application's state machine.
|
|
14319
|
+
*
|
|
14320
|
+
* Example:
|
|
14321
|
+
* `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
|
|
14322
|
+
*/
|
|
14323
|
+
state(target) {
|
|
14324
|
+
const observe = async (machineName, stateName, input = {}) => {
|
|
14325
|
+
const observedState = input.observedState || input.state || stateName;
|
|
14326
|
+
if (!observedState) {
|
|
14327
|
+
throw new Error("State observation requires a target state");
|
|
14328
|
+
}
|
|
14329
|
+
return this.recordState({
|
|
14330
|
+
...target,
|
|
14331
|
+
machine: machineName,
|
|
14332
|
+
state: observedState,
|
|
14333
|
+
...input.source ? { source: input.source } : {},
|
|
14334
|
+
...input.cause ? { cause: input.cause } : {},
|
|
14335
|
+
...input.actorId ? { actorId: input.actorId } : {},
|
|
14336
|
+
...input.observedAt !== void 0 ? { observedAt: input.observedAt } : {},
|
|
14337
|
+
...input.force !== void 0 ? { force: input.force } : {},
|
|
14338
|
+
...input.metadata ? { metadata: input.metadata } : {}
|
|
14339
|
+
});
|
|
14340
|
+
};
|
|
14341
|
+
return new Proxy(
|
|
14342
|
+
{},
|
|
14343
|
+
{
|
|
14344
|
+
get: (_target, machineProperty) => {
|
|
14345
|
+
if (typeof machineProperty !== "string") return void 0;
|
|
14346
|
+
return new Proxy(
|
|
14347
|
+
{},
|
|
14348
|
+
{
|
|
14349
|
+
get: (_machineTarget, stateProperty) => {
|
|
14350
|
+
if (stateProperty === "to") {
|
|
14351
|
+
return (stateName, input) => observe(machineProperty, stateName, input || {});
|
|
14352
|
+
}
|
|
14353
|
+
if (typeof stateProperty !== "string") return void 0;
|
|
14354
|
+
return (input) => observe(
|
|
14355
|
+
machineProperty,
|
|
14356
|
+
stateNameFromMethodName(stateProperty),
|
|
14357
|
+
input || {}
|
|
14358
|
+
);
|
|
14359
|
+
}
|
|
14360
|
+
}
|
|
14361
|
+
);
|
|
14362
|
+
}
|
|
14363
|
+
}
|
|
14364
|
+
);
|
|
14365
|
+
}
|
|
13529
14366
|
get feedback() {
|
|
13530
14367
|
return {
|
|
13531
14368
|
list: async () => this.listFeedback()
|
|
13532
14369
|
};
|
|
13533
14370
|
}
|
|
14371
|
+
get manualActions() {
|
|
14372
|
+
return {
|
|
14373
|
+
record: (input) => this.recordManualAction(input),
|
|
14374
|
+
list: (options = {}) => this.listManualActions(options),
|
|
14375
|
+
suggest: (options = {}) => this.suggestManualActions(options)
|
|
14376
|
+
};
|
|
14377
|
+
}
|
|
14378
|
+
get artifactApprovals() {
|
|
14379
|
+
return {
|
|
14380
|
+
list: (options = {}) => this.listArtifactApprovals(options),
|
|
14381
|
+
decide: (approvalTaskId, input) => this.decideArtifactApproval(approvalTaskId, input)
|
|
14382
|
+
};
|
|
14383
|
+
}
|
|
13534
14384
|
/**
|
|
13535
14385
|
* Sessionless environments do not own a live transport, so disconnecting the
|
|
13536
14386
|
* environment handle itself is a no-op. This keeps the public surface
|
|
@@ -13609,6 +14459,50 @@ var Environment = class _Environment {
|
|
|
13609
14459
|
const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
|
|
13610
14460
|
return Array.isArray(response.items) ? response.items : [];
|
|
13611
14461
|
}
|
|
14462
|
+
async recordManualAction(input) {
|
|
14463
|
+
const body = {
|
|
14464
|
+
...input,
|
|
14465
|
+
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
|
|
14466
|
+
};
|
|
14467
|
+
return this.controlPlaneRequest(
|
|
14468
|
+
`/control/environments/${this.environmentId}/manual-actions`,
|
|
14469
|
+
{
|
|
14470
|
+
method: "POST",
|
|
14471
|
+
body: JSON.stringify(body)
|
|
14472
|
+
}
|
|
14473
|
+
);
|
|
14474
|
+
}
|
|
14475
|
+
async listManualActions(options = {}) {
|
|
14476
|
+
const query = new URLSearchParams();
|
|
14477
|
+
appendQueryOptions(query, options);
|
|
14478
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14479
|
+
return this.controlPlaneRequest(`/control/environments/${this.environmentId}/manual-actions${suffix}`);
|
|
14480
|
+
}
|
|
14481
|
+
async suggestManualActions(options = {}) {
|
|
14482
|
+
const query = new URLSearchParams();
|
|
14483
|
+
appendQueryOptions(query, options);
|
|
14484
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14485
|
+
return this.controlPlaneRequest(
|
|
14486
|
+
`/control/environments/${this.environmentId}/manual-actions/suggestions${suffix}`
|
|
14487
|
+
);
|
|
14488
|
+
}
|
|
14489
|
+
async listArtifactApprovals(options = {}) {
|
|
14490
|
+
const query = new URLSearchParams();
|
|
14491
|
+
appendQueryOptions(query, options);
|
|
14492
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14493
|
+
return this.controlPlaneRequest(
|
|
14494
|
+
`/control/environments/${this.environmentId}/artifact-approvals${suffix}`
|
|
14495
|
+
);
|
|
14496
|
+
}
|
|
14497
|
+
async decideArtifactApproval(approvalTaskId, input) {
|
|
14498
|
+
return this.controlPlaneRequest(
|
|
14499
|
+
`/control/environments/${this.environmentId}/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
14500
|
+
{
|
|
14501
|
+
method: "POST",
|
|
14502
|
+
body: JSON.stringify(input)
|
|
14503
|
+
}
|
|
14504
|
+
);
|
|
14505
|
+
}
|
|
13612
14506
|
getRuntimeBaseUrl() {
|
|
13613
14507
|
return deriveRuntimeBaseUrl(this._apiEndpoint);
|
|
13614
14508
|
}
|
|
@@ -14433,10 +15327,11 @@ var Environment = class _Environment {
|
|
|
14433
15327
|
if (!Array.isArray(records) || records.length === 0) {
|
|
14434
15328
|
return [];
|
|
14435
15329
|
}
|
|
15330
|
+
const recordsToWrite = records.map(preserveRecordObjectRealId);
|
|
14436
15331
|
const batchSize = Math.max(
|
|
14437
15332
|
1,
|
|
14438
15333
|
Math.min(
|
|
14439
|
-
|
|
15334
|
+
recordsToWrite.length,
|
|
14440
15335
|
options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
|
|
14441
15336
|
)
|
|
14442
15337
|
);
|
|
@@ -14444,8 +15339,8 @@ var Environment = class _Environment {
|
|
|
14444
15339
|
MAX_RECORD_OBJECTS_CONCURRENCY,
|
|
14445
15340
|
Math.max(1, options?.concurrency ?? 1)
|
|
14446
15341
|
);
|
|
14447
|
-
const plans = planRecordObjectsChunks(
|
|
14448
|
-
const total =
|
|
15342
|
+
const plans = planRecordObjectsChunks(recordsToWrite, batchSize);
|
|
15343
|
+
const total = recordsToWrite.length;
|
|
14449
15344
|
const results = new Array(total);
|
|
14450
15345
|
const onChunk = options?.onChunkComplete;
|
|
14451
15346
|
for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
|
|
@@ -14516,12 +15411,13 @@ var Environment = class _Environment {
|
|
|
14516
15411
|
* synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
|
|
14517
15412
|
*/
|
|
14518
15413
|
async enqueueRecordImport(records, options = {}) {
|
|
15414
|
+
const recordsToImport = records.map(preserveRecordObjectRealId);
|
|
14519
15415
|
return this.controlPlaneRequest(
|
|
14520
15416
|
`/control/environments/${this.environmentId}/record-imports`,
|
|
14521
15417
|
{
|
|
14522
15418
|
method: "POST",
|
|
14523
15419
|
body: JSON.stringify({
|
|
14524
|
-
records,
|
|
15420
|
+
records: recordsToImport,
|
|
14525
15421
|
batchSize: options.batchSize,
|
|
14526
15422
|
setupRunId: options.setupRunId,
|
|
14527
15423
|
writeMode: options.writeMode
|
|
@@ -14629,11 +15525,7 @@ var EnvironmentSession = class extends Session {
|
|
|
14629
15525
|
}
|
|
14630
15526
|
buildSessionDataUrl(path, query) {
|
|
14631
15527
|
const searchParams = new URLSearchParams();
|
|
14632
|
-
|
|
14633
|
-
if (value !== null && typeof value !== "undefined" && value !== "") {
|
|
14634
|
-
searchParams.set(key, String(value));
|
|
14635
|
-
}
|
|
14636
|
-
}
|
|
15528
|
+
appendQueryOptions(searchParams, query);
|
|
14637
15529
|
const queryString = searchParams.toString();
|
|
14638
15530
|
return `${this.environment.runtimeBaseUrl}${this.sessionDataRoutePrefix}/${encodeURIComponent(this.sessionId)}${path}${queryString ? `?${queryString}` : ""}`;
|
|
14639
15531
|
}
|
|
@@ -14716,9 +15608,108 @@ var EnvironmentSession = class extends Session {
|
|
|
14716
15608
|
),
|
|
14717
15609
|
get: (jobId) => this.sessionDataRequest(
|
|
14718
15610
|
`/jobs/${encodeURIComponent(jobId)}`
|
|
15611
|
+
),
|
|
15612
|
+
latest: async (options = {}) => {
|
|
15613
|
+
const page = await this.sessionDataRequest("/jobs", {
|
|
15614
|
+
status: options.status || "all",
|
|
15615
|
+
latest: true,
|
|
15616
|
+
limit: 1
|
|
15617
|
+
});
|
|
15618
|
+
return page.items[0] || null;
|
|
15619
|
+
}
|
|
15620
|
+
};
|
|
15621
|
+
}
|
|
15622
|
+
get artifacts() {
|
|
15623
|
+
return {
|
|
15624
|
+
list: (options = {}) => {
|
|
15625
|
+
const queryOptions = { ...options };
|
|
15626
|
+
if (options.target) {
|
|
15627
|
+
queryOptions.targetClassName = options.target.className;
|
|
15628
|
+
queryOptions.targetId = options.target.id;
|
|
15629
|
+
delete queryOptions.target;
|
|
15630
|
+
}
|
|
15631
|
+
return this.sessionDataRequest("/artifacts", queryOptions);
|
|
15632
|
+
},
|
|
15633
|
+
listForLatestJob: (options = {}) => this.artifacts.list({
|
|
15634
|
+
...options,
|
|
15635
|
+
latestJob: true
|
|
15636
|
+
}),
|
|
15637
|
+
get: (artifactId) => this.sessionDataRequest(
|
|
15638
|
+
`/artifacts/${encodeURIComponent(artifactId)}`
|
|
15639
|
+
),
|
|
15640
|
+
create: (artifact) => this.sessionDataRequest(
|
|
15641
|
+
"/artifacts",
|
|
15642
|
+
void 0,
|
|
15643
|
+
{
|
|
15644
|
+
method: "POST",
|
|
15645
|
+
body: artifact
|
|
15646
|
+
}
|
|
15647
|
+
),
|
|
15648
|
+
updateInputs: (artifactId, patch) => this.sessionDataRequest(
|
|
15649
|
+
`/artifacts/${encodeURIComponent(artifactId)}`,
|
|
15650
|
+
void 0,
|
|
15651
|
+
{
|
|
15652
|
+
method: "PATCH",
|
|
15653
|
+
body: patch
|
|
15654
|
+
}
|
|
15655
|
+
),
|
|
15656
|
+
validate: (artifactId) => this.sessionDataRequest(
|
|
15657
|
+
`/artifacts/${encodeURIComponent(artifactId)}/validate`,
|
|
15658
|
+
void 0,
|
|
15659
|
+
{ method: "POST" }
|
|
15660
|
+
),
|
|
15661
|
+
execute: (artifactId, options) => this.sessionDataRequest(
|
|
15662
|
+
`/artifacts/${encodeURIComponent(artifactId)}/execute`,
|
|
15663
|
+
void 0,
|
|
15664
|
+
{ method: "POST", body: options }
|
|
15665
|
+
),
|
|
15666
|
+
approve: (artifactId, options) => this.sessionDataRequest(
|
|
15667
|
+
`/artifacts/${encodeURIComponent(artifactId)}/approve`,
|
|
15668
|
+
void 0,
|
|
15669
|
+
{ method: "POST", body: options }
|
|
15670
|
+
),
|
|
15671
|
+
cancel: (artifactId) => this.sessionDataRequest(
|
|
15672
|
+
`/artifacts/${encodeURIComponent(artifactId)}/cancel`,
|
|
15673
|
+
void 0,
|
|
15674
|
+
{ method: "POST" }
|
|
14719
15675
|
)
|
|
14720
15676
|
};
|
|
14721
15677
|
}
|
|
15678
|
+
get manualActions() {
|
|
15679
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15680
|
+
return {
|
|
15681
|
+
record: (input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15682
|
+
"/manual-actions",
|
|
15683
|
+
void 0,
|
|
15684
|
+
{
|
|
15685
|
+
method: "POST",
|
|
15686
|
+
body: { ...input, sessionId: this.sessionId }
|
|
15687
|
+
}
|
|
15688
|
+
) : this.environment.manualActions.record({
|
|
15689
|
+
...input,
|
|
15690
|
+
sessionId: this.sessionId
|
|
15691
|
+
}),
|
|
15692
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/manual-actions", { ...options, sessionId: this.sessionId }) : this.environment.manualActions.list({
|
|
15693
|
+
...options,
|
|
15694
|
+
sessionId: this.sessionId
|
|
15695
|
+
}),
|
|
15696
|
+
suggest: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15697
|
+
"/manual-actions/suggestions",
|
|
15698
|
+
options
|
|
15699
|
+
) : this.environment.manualActions.suggest(options)
|
|
15700
|
+
};
|
|
15701
|
+
}
|
|
15702
|
+
get artifactApprovals() {
|
|
15703
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15704
|
+
return {
|
|
15705
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/artifact-approvals", options) : this.environment.artifactApprovals.list(options),
|
|
15706
|
+
decide: (approvalTaskId, input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15707
|
+
`/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
15708
|
+
void 0,
|
|
15709
|
+
{ method: "POST", body: input }
|
|
15710
|
+
) : this.environment.artifactApprovals.decide(approvalTaskId, input)
|
|
15711
|
+
};
|
|
15712
|
+
}
|
|
14722
15713
|
get files() {
|
|
14723
15714
|
return {
|
|
14724
15715
|
list: (options = {}) => this.sessionDataRequest(
|
|
@@ -14799,13 +15790,16 @@ var EnvironmentSession = class extends Session {
|
|
|
14799
15790
|
get transcript() {
|
|
14800
15791
|
return {
|
|
14801
15792
|
list: async (options = {}) => {
|
|
14802
|
-
const [messages, jobs, entries, lists] = await Promise.all([
|
|
15793
|
+
const [messages, jobs, entries, lists, artifacts] = await Promise.all([
|
|
14803
15794
|
this.collectAllSessionItems(this.messages.list),
|
|
14804
15795
|
this.collectAllSessionItems(
|
|
14805
15796
|
(pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
|
|
14806
15797
|
),
|
|
14807
15798
|
this.collectAllSessionItems(this.heap.entries.list),
|
|
14808
|
-
this.collectAllSessionItems(this.heap.lists.list)
|
|
15799
|
+
this.collectAllSessionItems(this.heap.lists.list),
|
|
15800
|
+
this.collectAllSessionItems(
|
|
15801
|
+
(pageOptions) => this.artifacts.list({ ...pageOptions, status: "all" })
|
|
15802
|
+
)
|
|
14809
15803
|
]);
|
|
14810
15804
|
const liveDoc = {
|
|
14811
15805
|
conversation: { messages },
|
|
@@ -14819,6 +15813,21 @@ var EnvironmentSession = class extends Session {
|
|
|
14819
15813
|
(entry) => Boolean(entry)
|
|
14820
15814
|
)
|
|
14821
15815
|
)
|
|
15816
|
+
},
|
|
15817
|
+
artifacts: {
|
|
15818
|
+
byId: Object.fromEntries(
|
|
15819
|
+
artifacts.map((artifact) => {
|
|
15820
|
+
return artifact?.artifactId ? [
|
|
15821
|
+
artifact.artifactId,
|
|
15822
|
+
artifact
|
|
15823
|
+
] : null;
|
|
15824
|
+
}).filter(
|
|
15825
|
+
(entry) => Boolean(entry)
|
|
15826
|
+
)
|
|
15827
|
+
),
|
|
15828
|
+
order: artifacts.map((artifact) => artifact?.artifactId).filter(
|
|
15829
|
+
(artifactId) => Boolean(artifactId)
|
|
15830
|
+
)
|
|
14822
15831
|
}
|
|
14823
15832
|
};
|
|
14824
15833
|
const heap = normalizeHeapSnapshot({
|
|
@@ -14895,6 +15904,12 @@ var EnvironmentSession = class extends Session {
|
|
|
14895
15904
|
async recordObject(options) {
|
|
14896
15905
|
return this.environment.recordObject(options);
|
|
14897
15906
|
}
|
|
15907
|
+
async recordState(input) {
|
|
15908
|
+
return this.environment.recordState(input);
|
|
15909
|
+
}
|
|
15910
|
+
state(target) {
|
|
15911
|
+
return this.environment.state(target);
|
|
15912
|
+
}
|
|
14898
15913
|
async recordObjects(records, options) {
|
|
14899
15914
|
return this.environment.recordObjects(records, options);
|
|
14900
15915
|
}
|
|
@@ -15722,15 +16737,43 @@ var Granular = class _Granular {
|
|
|
15722
16737
|
const effects = Array.from(
|
|
15723
16738
|
this.getSandboxEffectMap(host.sandboxId).values()
|
|
15724
16739
|
).map((effect) => this.serializeEffect(effect));
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
|
|
15733
|
-
|
|
16740
|
+
let acceptedCount = 0;
|
|
16741
|
+
const rejected = [];
|
|
16742
|
+
try {
|
|
16743
|
+
await withTimeout(
|
|
16744
|
+
host.wsClient.call("effects.resetCatalog", {}),
|
|
16745
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16746
|
+
`effects.resetCatalog for sandbox ${host.sandboxId}`
|
|
16747
|
+
);
|
|
16748
|
+
for (const batch of chunkItems(effects, EFFECT_CATALOG_SYNC_BATCH_SIZE)) {
|
|
16749
|
+
const result = await withTimeout(
|
|
16750
|
+
host.wsClient.call("effects.addCatalog", {
|
|
16751
|
+
effects: batch
|
|
16752
|
+
}),
|
|
16753
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16754
|
+
`effects.addCatalog for sandbox ${host.sandboxId}`
|
|
16755
|
+
);
|
|
16756
|
+
acceptedCount += typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16757
|
+
if (Array.isArray(result?.rejected)) {
|
|
16758
|
+
rejected.push(...result.rejected);
|
|
16759
|
+
}
|
|
16760
|
+
}
|
|
16761
|
+
} catch (error) {
|
|
16762
|
+
if (!isUnsupportedEffectCatalogMutation(error)) {
|
|
16763
|
+
throw error;
|
|
16764
|
+
}
|
|
16765
|
+
const result = await withTimeout(
|
|
16766
|
+
host.wsClient.call("effects.publishCatalog", {
|
|
16767
|
+
effects
|
|
16768
|
+
}),
|
|
16769
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16770
|
+
`effects.publishCatalog for sandbox ${host.sandboxId}`
|
|
16771
|
+
);
|
|
16772
|
+
acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16773
|
+
if (Array.isArray(result?.rejected)) {
|
|
16774
|
+
rejected.push(...result.rejected);
|
|
16775
|
+
}
|
|
16776
|
+
}
|
|
15734
16777
|
if (acceptedCount === 0 && rejected.length > 0) {
|
|
15735
16778
|
const detail = rejected.map(
|
|
15736
16779
|
(entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`
|
|
@@ -16962,6 +18005,7 @@ var HARNESS_V3_FRONTEND_ACTIONS_MODULE = "@granular/actions/frontend";
|
|
|
16962
18005
|
var HARNESS_V3_CSV_MODULE = "@granular/utils/csv";
|
|
16963
18006
|
var HARNESS_V3_XLSX_MODULE = "@granular/utils/xlsx";
|
|
16964
18007
|
var LEGACY_SANDBOX_TOOLS_MODULE_PATTERN = "\\.\\/sandbox-tools(?:\\.js)?";
|
|
18008
|
+
var HARNESS_V3_RUNTIME_MODULE_PATTERN = "@granular/(?:agent|session|domain(?:/[A-Za-z_$][\\w$]*)?|actions/(?:backend|frontend)|utils/(?:csv|xlsx))";
|
|
16965
18009
|
function hasNamedModuleImport(source, moduleName, name) {
|
|
16966
18010
|
const escapedModule = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16967
18011
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -17020,6 +18064,15 @@ function reviewGeneratedJobCode(code, _options = {}) {
|
|
|
17020
18064
|
message: "Generated code must use static top-level ESM imports from the Harness v3 runtime modules. Do not use dynamic import(...)."
|
|
17021
18065
|
});
|
|
17022
18066
|
}
|
|
18067
|
+
if (new RegExp(
|
|
18068
|
+
`import\\s+\\*\\s+as\\s+[A-Za-z_$][\\w$]*\\s+from\\s*['"]${HARNESS_V3_RUNTIME_MODULE_PATTERN}['"]`
|
|
18069
|
+
).test(normalized)) {
|
|
18070
|
+
issues.push({
|
|
18071
|
+
code: "runtime_namespace_import",
|
|
18072
|
+
severity: "error",
|
|
18073
|
+
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"`.'
|
|
18074
|
+
});
|
|
18075
|
+
}
|
|
17023
18076
|
if (/\bprocess\.exit\s*\(/.test(normalized)) {
|
|
17024
18077
|
issues.push({
|
|
17025
18078
|
code: "process_exit",
|
|
@@ -18044,6 +19097,31 @@ function buildGranularAgentHeapBlock(heapSummary) {
|
|
|
18044
19097
|
entries: {}
|
|
18045
19098
|
});
|
|
18046
19099
|
}
|
|
19100
|
+
function buildGranularAgentManualActionMemorySummary(input) {
|
|
19101
|
+
const maxItems = Math.max(1, Math.min(12, input.maxItems ?? 8));
|
|
19102
|
+
const suggestions = (input.suggestions || []).filter((suggestion) => suggestion?.actionKey).slice(0, maxItems).map((suggestion) => ({
|
|
19103
|
+
actionKey: suggestion.actionKey,
|
|
19104
|
+
label: suggestion.label || null,
|
|
19105
|
+
targetClassName: suggestion.targetClassName || null,
|
|
19106
|
+
count: typeof suggestion.count === "number" && Number.isFinite(suggestion.count) ? suggestion.count : null,
|
|
19107
|
+
subjectCount: typeof suggestion.subjectCount === "number" && Number.isFinite(suggestion.subjectCount) ? suggestion.subjectCount : null,
|
|
19108
|
+
successCount: typeof suggestion.successCount === "number" && Number.isFinite(suggestion.successCount) ? suggestion.successCount : null,
|
|
19109
|
+
failureCount: typeof suggestion.failureCount === "number" && Number.isFinite(suggestion.failureCount) ? suggestion.failureCount : null,
|
|
19110
|
+
lastOccurredAt: typeof suggestion.lastOccurredAt === "number" && Number.isFinite(suggestion.lastOccurredAt) ? suggestion.lastOccurredAt : null,
|
|
19111
|
+
sampleTargetIds: Array.isArray(suggestion.sampleTargetIds) ? suggestion.sampleTargetIds.filter(
|
|
19112
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
19113
|
+
).slice(0, 6) : []
|
|
19114
|
+
}));
|
|
19115
|
+
return [
|
|
19116
|
+
renderConstBlock("manualActionMemory", {
|
|
19117
|
+
suggestions
|
|
19118
|
+
}),
|
|
19119
|
+
"Use manualActionMemory only as behavioral context for likely next actions. Ground the current target and validate permissions before creating or running prepared actions."
|
|
19120
|
+
].join("\n");
|
|
19121
|
+
}
|
|
19122
|
+
function buildGranularAgentManualActionBlock(manualActionSummary) {
|
|
19123
|
+
return manualActionSummary?.trim() || buildGranularAgentManualActionMemorySummary({ suggestions: [] });
|
|
19124
|
+
}
|
|
18047
19125
|
function projectSessionFileSummary(liveDoc) {
|
|
18048
19126
|
const files = asRecord4(liveDoc?.files);
|
|
18049
19127
|
const byId = asRecord4(files?.byId) || {};
|
|
@@ -18075,8 +19153,12 @@ function buildGranularAgentFileBlock(fileSummary) {
|
|
|
18075
19153
|
function extractRuntimeContractExports(domainBlock) {
|
|
18076
19154
|
const classes = /* @__PURE__ */ new Set();
|
|
18077
19155
|
const actions = /* @__PURE__ */ new Set();
|
|
18078
|
-
const
|
|
18079
|
-
for (const match of domainBlock.matchAll(
|
|
19156
|
+
const classConstPattern = /export\s+declare\s+const\s+([A-Za-z_$][\w$]*)\s*:\s*EntityClass\b/g;
|
|
19157
|
+
for (const match of domainBlock.matchAll(classConstPattern)) {
|
|
19158
|
+
classes.add(match[1]);
|
|
19159
|
+
}
|
|
19160
|
+
const classDeclPattern = /export\s+declare\s+class\s+([A-Za-z_$][\w$]*)\b/g;
|
|
19161
|
+
for (const match of domainBlock.matchAll(classDeclPattern)) {
|
|
18080
19162
|
classes.add(match[1]);
|
|
18081
19163
|
}
|
|
18082
19164
|
const actionPattern = /export\s+declare\s+function\s+([A-Za-z_$][\w$]*)/g;
|
|
@@ -18581,6 +19663,9 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18581
19663
|
});
|
|
18582
19664
|
const referentBlock = buildGranularAgentReferentBlock(input.referentSummary);
|
|
18583
19665
|
const loopBlock = buildGranularAgentLoopBlock(input.loopSummary);
|
|
19666
|
+
const manualActionBlock = buildGranularAgentManualActionBlock(
|
|
19667
|
+
input.manualActionSummary
|
|
19668
|
+
);
|
|
18584
19669
|
const knownFactsBlock = renderConstBlock(
|
|
18585
19670
|
"knownFacts",
|
|
18586
19671
|
buildKnownFactsFromCheckpoint(input.checkpoint)
|
|
@@ -18594,16 +19679,15 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18594
19679
|
- \`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.
|
|
18595
19680
|
- 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.
|
|
18596
19681
|
- 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.
|
|
18597
|
-
- When \`replyToUser(...)\` mentions a grounded record that should remain clickable/referable, wrap only the visible record label in a self-closing inline reference tag
|
|
18598
|
-
- Treat \`showObjects(...)\` as the UI display call for user-visible records,
|
|
18599
|
-
-
|
|
18600
|
-
-
|
|
18601
|
-
-
|
|
18602
|
-
-
|
|
19682
|
+
- 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.
|
|
19683
|
+
- 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"] })\`.
|
|
19684
|
+
- \`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(...)\`.
|
|
19685
|
+
- 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.
|
|
19686
|
+
- 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()\`.
|
|
19687
|
+
- 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.
|
|
18603
19688
|
- 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.
|
|
18604
19689
|
- 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.
|
|
18605
|
-
-
|
|
18606
|
-
- 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.
|
|
19690
|
+
- 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.
|
|
18607
19691
|
- 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\`.
|
|
18608
19692
|
- \`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.
|
|
18609
19693
|
- 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.
|
|
@@ -18614,7 +19698,7 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18614
19698
|
- When using code, assistant text must be empty or one brief summary.
|
|
18615
19699
|
- Code must be plain runnable JavaScript with top-level await.
|
|
18616
19700
|
- Use [Runtime Imports] as the authoritative module map. Import only listed module exports.
|
|
18617
|
-
- 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.
|
|
19701
|
+
- 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.
|
|
18618
19702
|
- 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.
|
|
18619
19703
|
- 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.
|
|
18620
19704
|
- 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\`.
|
|
@@ -18677,6 +19761,7 @@ ${workflowRules}
|
|
|
18677
19761
|
High-priority execution rules:
|
|
18678
19762
|
- 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.
|
|
18679
19763
|
- 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.
|
|
19764
|
+
- 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.
|
|
18680
19765
|
- 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.
|
|
18681
19766
|
- 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.
|
|
18682
19767
|
- 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.
|
|
@@ -18720,7 +19805,7 @@ Intent resolution:
|
|
|
18720
19805
|
- 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.
|
|
18721
19806
|
- 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.
|
|
18722
19807
|
- 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.
|
|
18723
|
-
- 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
|
|
19808
|
+
- 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.
|
|
18724
19809
|
- 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.
|
|
18725
19810
|
- Never call \`.get({ path: "" })\`; an empty path is not a saved reference.
|
|
18726
19811
|
- 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.
|
|
@@ -18847,20 +19932,10 @@ Ask the user when:
|
|
|
18847
19932
|
- the target is unique but the requested action is unclear
|
|
18848
19933
|
|
|
18849
19934
|
Relationship filters:
|
|
18850
|
-
-
|
|
18851
|
-
-
|
|
18852
|
-
-
|
|
18853
|
-
-
|
|
18854
|
-
- 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.
|
|
18855
|
-
- 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.
|
|
18856
|
-
- Use \`some\` only when the generated TypeScript type says \`ManyRelationFilter\`.
|
|
18857
|
-
- 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.
|
|
18858
|
-
- Use \`{ relationship: { id: "record_id" } }\` or \`{ relationship: { path: "class_record_id" } }\` when matching a known related record.
|
|
18859
|
-
- 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\`.
|
|
18860
|
-
- 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.
|
|
18861
|
-
- Use \`{ relationship: { is: { field: { equal_to: value } } } }\` only for nested field filters. Never put \`id\` or \`path\` inside \`is\`.
|
|
18862
|
-
- 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.
|
|
18863
|
-
- Do not pass a full record instance into a filter; if you already fetched a record, filter by its id or path instead.
|
|
19935
|
+
- Use the generated filter type as the authority: \`OneRelationFilter\` supports \`id\`, \`path\`, \`is\`, \`null\`, \`not_null\`; \`ManyRelationFilter\` supports those plus \`some\`.
|
|
19936
|
+
- Use \`id\` or \`path\` for a known related record; use \`is\` or \`some\` only for nested target-field filters.
|
|
19937
|
+
- 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.
|
|
19938
|
+
- Never pass a full record instance into a filter. Use its id/path or a declared relationship getter.
|
|
18864
19939
|
${domainSections.docs ? `
|
|
18865
19940
|
Domain notes:
|
|
18866
19941
|
${domainSections.docs}
|
|
@@ -18871,6 +19946,23 @@ ${actionIndex}
|
|
|
18871
19946
|
- 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.
|
|
18872
19947
|
- 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(...)\`.
|
|
18873
19948
|
- Actions listed under "Class-level" are class/static methods. Call them on the imported class, e.g. \`await Item.action_name(...)\`.
|
|
19949
|
+
- 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.
|
|
19950
|
+
- For pure field-collection requests, target the class-level entry state handle; for submit/review requests, target the nearest requested later state.
|
|
19951
|
+
- Choose the nearest target state that matches the user's words. Do not aim at a later state just because it is reachable.
|
|
19952
|
+
- 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\`.
|
|
19953
|
+
- 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.
|
|
19954
|
+
- 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.
|
|
19955
|
+
- 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()\`.
|
|
19956
|
+
- 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.
|
|
19957
|
+
- 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.
|
|
19958
|
+
- 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.
|
|
19959
|
+
- 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.
|
|
19960
|
+
- 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.
|
|
19961
|
+
- 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.
|
|
19962
|
+
- 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.
|
|
19963
|
+
- 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.
|
|
19964
|
+
- 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.
|
|
19965
|
+
- Use \`await prepared.show()\` or \`await actions.show(prepared)\` only to display an already-created prepared action again.
|
|
18874
19966
|
- 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.
|
|
18875
19967
|
- Never call a record-level action as \`Class.action_name(...)\`; that method will not exist.
|
|
18876
19968
|
- 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.
|
|
@@ -18901,6 +19993,8 @@ ${loopBlock}
|
|
|
18901
19993
|
|
|
18902
19994
|
${knownFactsBlock}
|
|
18903
19995
|
|
|
19996
|
+
${manualActionBlock}
|
|
19997
|
+
|
|
18904
19998
|
[Request]
|
|
18905
19999
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
18906
20000
|
}
|
|
@@ -19202,6 +20296,8 @@ exports.buildGranularAgentDomainBlock = buildGranularAgentDomainBlock;
|
|
|
19202
20296
|
exports.buildGranularAgentFileBlock = buildGranularAgentFileBlock;
|
|
19203
20297
|
exports.buildGranularAgentHeapBlock = buildGranularAgentHeapBlock;
|
|
19204
20298
|
exports.buildGranularAgentLoopBlock = buildGranularAgentLoopBlock;
|
|
20299
|
+
exports.buildGranularAgentManualActionBlock = buildGranularAgentManualActionBlock;
|
|
20300
|
+
exports.buildGranularAgentManualActionMemorySummary = buildGranularAgentManualActionMemorySummary;
|
|
19205
20301
|
exports.buildGranularAgentReferentBlock = buildGranularAgentReferentBlock;
|
|
19206
20302
|
exports.buildGranularAgentRuntimeImportsBlock = buildGranularAgentRuntimeImportsBlock;
|
|
19207
20303
|
exports.buildGranularAgentSessionBlock = buildGranularAgentSessionBlock;
|
|
@@ -19216,6 +20312,7 @@ exports.consumeGranularReasoningOnlyChunk = consumeGranularReasoningOnlyChunk;
|
|
|
19216
20312
|
exports.consumeGranularReasoningTraceChunk = consumeGranularReasoningTraceChunk;
|
|
19217
20313
|
exports.createHarnessVerifierSnapshot = createHarnessVerifierSnapshot;
|
|
19218
20314
|
exports.evaluateContinuation = evaluateContinuation;
|
|
20315
|
+
exports.evaluateValidationRule = evaluateValidationRule;
|
|
19219
20316
|
exports.extractPromptTokens = extractPromptTokens;
|
|
19220
20317
|
exports.getCurrentClosureId = getCurrentClosureId;
|
|
19221
20318
|
exports.getDefaultHarnessTemplateId = getDefaultHarnessTemplateId;
|
|
@@ -19252,5 +20349,6 @@ exports.scorePromptChoiceMatch = scorePromptChoiceMatch;
|
|
|
19252
20349
|
exports.stripGranularReasoningTrace = stripGranularReasoningTrace;
|
|
19253
20350
|
exports.toGranularHttpBase = toGranularHttpBase;
|
|
19254
20351
|
exports.validateHarnessTemplateManifest = validateHarnessTemplateManifest;
|
|
20352
|
+
exports.validationRuleFailureMessage = validationRuleFailureMessage;
|
|
19255
20353
|
//# sourceMappingURL=index.js.map
|
|
19256
20354
|
//# sourceMappingURL=index.js.map
|