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