@granular-software/sdk 0.4.49 → 0.4.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-evals.d.mts +2 -2
- package/dist/agent-evals.d.ts +2 -2
- package/dist/agent-evals.js +1107 -103
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +1107 -103
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.d.mts +19 -2
- package/dist/agent-harness.d.ts +19 -2
- package/dist/agent-harness.js +79 -26
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +78 -27
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +1008 -66
- package/dist/{client-B-MPVvDr.d.mts → client-BbI7ThzU.d.ts} +62 -1
- package/dist/{client-zihxkDDs.d.ts → client-DaYFTHG8.d.mts} +62 -1
- package/dist/index.d.mts +104 -5
- package/dist/index.d.ts +104 -5
- package/dist/index.js +1189 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1186 -95
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-CStuOBXb.d.mts → spend-RpJikX9w.d.mts} +383 -11
- package/dist/{spend-CStuOBXb.d.ts → spend-RpJikX9w.d.ts} +383 -11
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/package.json +2 -1
package/dist/agent-evals.mjs
CHANGED
|
@@ -4019,6 +4019,9 @@ function rpcTimeoutMsForMethod(method) {
|
|
|
4019
4019
|
return DOMAIN_PACKAGE_RPC_TIMEOUT_MS;
|
|
4020
4020
|
case "client.heartbeat":
|
|
4021
4021
|
case "effects.publishCatalog":
|
|
4022
|
+
case "effects.resetCatalog":
|
|
4023
|
+
case "effects.addCatalog":
|
|
4024
|
+
case "effects.removeCatalog":
|
|
4022
4025
|
case "effects.refresh":
|
|
4023
4026
|
return EFFECT_CONTROL_RPC_TIMEOUT_MS;
|
|
4024
4027
|
case "harness.run":
|
|
@@ -4764,6 +4767,9 @@ function resolvePromptAnswer(prompt, answer) {
|
|
|
4764
4767
|
|
|
4765
4768
|
// src/session.ts
|
|
4766
4769
|
var PROMPT_TRANSCRIPT_APPEND_TIMEOUT_MS = 5e3;
|
|
4770
|
+
function toPascalCase(value) {
|
|
4771
|
+
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
4772
|
+
}
|
|
4767
4773
|
function withPromptTranscriptTimeout(promise) {
|
|
4768
4774
|
let timeout = null;
|
|
4769
4775
|
return Promise.race([
|
|
@@ -5326,9 +5332,7 @@ var Session = class {
|
|
|
5326
5332
|
if (classes && Object.keys(classes).length > 0) {
|
|
5327
5333
|
let docs2 = "# Domain Documentation\n\n";
|
|
5328
5334
|
docs2 += "Import concrete classes from `@granular/domain/<Class>` and global backend actions from `@granular/actions/backend`:\n\n";
|
|
5329
|
-
const classNames = Object.keys(classes).map(
|
|
5330
|
-
(c) => c.charAt(0).toUpperCase() + c.slice(1)
|
|
5331
|
-
);
|
|
5335
|
+
const classNames = Object.keys(classes).map(toPascalCase);
|
|
5332
5336
|
const globalNames = (globalTools || []).map((t) => t.name);
|
|
5333
5337
|
const importLines = [
|
|
5334
5338
|
...classNames.map(
|
|
@@ -5342,7 +5346,7 @@ ${importLines.join("\n") || "// No generated domain imports available."}
|
|
|
5342
5346
|
|
|
5343
5347
|
`;
|
|
5344
5348
|
for (const [className, cls] of Object.entries(classes)) {
|
|
5345
|
-
const TsName =
|
|
5349
|
+
const TsName = toPascalCase(className);
|
|
5346
5350
|
docs2 += `## ${TsName}
|
|
5347
5351
|
|
|
5348
5352
|
`;
|
|
@@ -6332,6 +6336,28 @@ function asString(value) {
|
|
|
6332
6336
|
function trimString(value) {
|
|
6333
6337
|
return typeof value === "string" ? value.trim() : "";
|
|
6334
6338
|
}
|
|
6339
|
+
function compactJson(value, maxLength = 320) {
|
|
6340
|
+
if (value === void 0 || value === null) return void 0;
|
|
6341
|
+
try {
|
|
6342
|
+
const json = JSON.stringify(value);
|
|
6343
|
+
if (!json || json === "undefined") return void 0;
|
|
6344
|
+
return json.length > maxLength ? `${json.slice(0, maxLength)}...` : json;
|
|
6345
|
+
} catch {
|
|
6346
|
+
return String(value);
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6349
|
+
function artifactRecordsById(liveDoc) {
|
|
6350
|
+
const artifacts = asRecord3(liveDoc?.artifacts);
|
|
6351
|
+
const byId = asRecord3(artifacts?.byId) || {};
|
|
6352
|
+
return Object.fromEntries(
|
|
6353
|
+
Object.entries(byId).map(([artifactId, value]) => {
|
|
6354
|
+
const record = asRecord3(value);
|
|
6355
|
+
return record ? [artifactId, record] : null;
|
|
6356
|
+
}).filter(
|
|
6357
|
+
(entry) => Boolean(entry)
|
|
6358
|
+
)
|
|
6359
|
+
);
|
|
6360
|
+
}
|
|
6335
6361
|
function normalizeShowRefs(value) {
|
|
6336
6362
|
const record = asRecord3(value);
|
|
6337
6363
|
if (!record) return void 0;
|
|
@@ -6348,9 +6374,31 @@ function normalizeShowRefs(value) {
|
|
|
6348
6374
|
entryPaths: normalizeRefs(record.entryPaths),
|
|
6349
6375
|
listNames: normalizeRefs(record.listNames),
|
|
6350
6376
|
variableNames: normalizeRefs(record.variableNames),
|
|
6351
|
-
fileIds: normalizeRefs(record.fileIds)
|
|
6377
|
+
fileIds: normalizeRefs(record.fileIds),
|
|
6378
|
+
sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
|
|
6379
|
+
actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
|
|
6352
6380
|
};
|
|
6353
|
-
return show.entryPaths || show.listNames || show.variableNames || show.fileIds ? show : void 0;
|
|
6381
|
+
return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions ? show : void 0;
|
|
6382
|
+
}
|
|
6383
|
+
function normalizeActionSuggestions(value) {
|
|
6384
|
+
if (!Array.isArray(value)) return void 0;
|
|
6385
|
+
const suggestions = [];
|
|
6386
|
+
for (const item of value) {
|
|
6387
|
+
const record = asRecord3(item);
|
|
6388
|
+
if (!record) continue;
|
|
6389
|
+
const label = trimString(record.label);
|
|
6390
|
+
if (!label) continue;
|
|
6391
|
+
const suggestionId = trimString(record.suggestionId) || trimString(record.id) || label;
|
|
6392
|
+
suggestions.push({
|
|
6393
|
+
suggestionId,
|
|
6394
|
+
label,
|
|
6395
|
+
...typeof record.description === "string" ? { description: record.description } : {},
|
|
6396
|
+
...asRecord3(record.artifact) ? { artifact: asRecord3(record.artifact) } : {},
|
|
6397
|
+
...asRecord3(record.target) ? { target: asRecord3(record.target) } : {},
|
|
6398
|
+
...asRecord3(record.metadata) ? { metadata: asRecord3(record.metadata) } : {}
|
|
6399
|
+
});
|
|
6400
|
+
}
|
|
6401
|
+
return suggestions.length ? suggestions : void 0;
|
|
6354
6402
|
}
|
|
6355
6403
|
function stringifyTranscriptValue(value, fallback = "") {
|
|
6356
6404
|
if (typeof value === "string") {
|
|
@@ -6370,12 +6418,139 @@ function stringifyTranscriptValue(value, fallback = "") {
|
|
|
6370
6418
|
return String(value);
|
|
6371
6419
|
}
|
|
6372
6420
|
}
|
|
6373
|
-
function
|
|
6421
|
+
function latestInputEditSummary(metadata) {
|
|
6422
|
+
const lastInputEdit = asRecord3(metadata.lastInputEdit);
|
|
6423
|
+
if (!lastInputEdit) return null;
|
|
6424
|
+
const source = asString(lastInputEdit.source) || "unknown";
|
|
6425
|
+
const actor = asString(lastInputEdit.actorSubjectId) || asString(lastInputEdit.actorPermissionProfileName) || asString(lastInputEdit.jobId) || null;
|
|
6426
|
+
const inputKeys = Array.isArray(lastInputEdit.changedInputKeys) ? lastInputEdit.changedInputKeys.filter(
|
|
6427
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6428
|
+
).slice(0, 6) : [];
|
|
6429
|
+
const relationshipKeys = Array.isArray(lastInputEdit.changedRelationshipKeys) ? lastInputEdit.changedRelationshipKeys.filter(
|
|
6430
|
+
(key) => typeof key === "string" && key.trim().length > 0
|
|
6431
|
+
).slice(0, 6) : [];
|
|
6432
|
+
const changed = [
|
|
6433
|
+
inputKeys.length ? `inputs=${inputKeys.join(",")}` : null,
|
|
6434
|
+
relationshipKeys.length ? `relationships=${relationshipKeys.join(",")}` : null
|
|
6435
|
+
].filter(Boolean);
|
|
6436
|
+
return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
|
|
6437
|
+
}
|
|
6438
|
+
function artifactIssueSummary(record) {
|
|
6439
|
+
const validation = asRecord3(record.validation);
|
|
6440
|
+
if (!validation) return null;
|
|
6441
|
+
const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
|
|
6442
|
+
if (issues.length > 0) {
|
|
6443
|
+
return `issues=${issues.map((issue) => {
|
|
6444
|
+
const code = asString(issue.code) || asString(issue.kind) || "issue";
|
|
6445
|
+
const path2 = asString(issue.path);
|
|
6446
|
+
const message = trimString(issue.message);
|
|
6447
|
+
return `${code}${path2 ? ` at ${path2}` : ""}${message ? ` (${message})` : ""}`;
|
|
6448
|
+
}).join("; ")}`;
|
|
6449
|
+
}
|
|
6450
|
+
const error = trimString(validation.error) || trimString(validation.reason) || trimString(validation.message);
|
|
6451
|
+
return error ? `validation=${error}` : null;
|
|
6452
|
+
}
|
|
6453
|
+
function artifactExecutionSummary(metadata) {
|
|
6454
|
+
const execution = asRecord3(metadata.execution);
|
|
6455
|
+
if (!execution) return null;
|
|
6456
|
+
const result = asRecord3(execution.result);
|
|
6457
|
+
const awaiting = asString(result?.awaiting) || asString(execution.awaiting);
|
|
6458
|
+
const pendingTransition = asString(result?.pendingTransition) || asString(execution.pendingTransition);
|
|
6459
|
+
const approval = asRecord3(result?.approval) || asRecord3(execution.approval);
|
|
6460
|
+
const approvalTarget = asString(approval?.permissionProfileName) || asString(approval?.permissionProfileId) || asString(approval?.assigneeSubjectId);
|
|
6461
|
+
const error = trimString(execution.error);
|
|
6462
|
+
const pieces = [
|
|
6463
|
+
awaiting ? `awaiting=${awaiting}` : null,
|
|
6464
|
+
pendingTransition ? `pendingTransition=${pendingTransition}` : null,
|
|
6465
|
+
approvalTarget ? `approvalTarget=${approvalTarget}` : null,
|
|
6466
|
+
error ? `executionError=${error}` : null
|
|
6467
|
+
].filter(Boolean);
|
|
6468
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6469
|
+
}
|
|
6470
|
+
function artifactStatePathSummary(metadata) {
|
|
6471
|
+
const statePlan = asRecord3(metadata.statePlan);
|
|
6472
|
+
if (!statePlan) return null;
|
|
6473
|
+
const machineName = asString(statePlan.machineName);
|
|
6474
|
+
const targetState = asString(statePlan.targetState);
|
|
6475
|
+
const objectPath = asString(statePlan.objectPath);
|
|
6476
|
+
const approvedTransitions = Array.isArray(statePlan.approvedTransitions) ? statePlan.approvedTransitions.length : 0;
|
|
6477
|
+
const approvalDecisions = Array.isArray(statePlan.approvalDecisions) ? statePlan.approvalDecisions.length : 0;
|
|
6478
|
+
const pieces = [
|
|
6479
|
+
machineName || targetState ? `statePath=${machineName || "state_machine"}${targetState ? ` -> ${targetState}` : ""}` : null,
|
|
6480
|
+
objectPath ? `objectPath=${objectPath}` : null,
|
|
6481
|
+
approvedTransitions ? `approvedTransitions=${approvedTransitions}` : null,
|
|
6482
|
+
approvalDecisions ? `approvalDecisions=${approvalDecisions}` : null
|
|
6483
|
+
].filter(Boolean);
|
|
6484
|
+
return pieces.length ? pieces.join("; ") : null;
|
|
6485
|
+
}
|
|
6486
|
+
function artifactSummaryLine(artifactId, record) {
|
|
6487
|
+
if (!record) return `- ${artifactId}: unavailable in session artifact store`;
|
|
6488
|
+
const label = trimString(record.label) || artifactId;
|
|
6489
|
+
const kind = asString(record.kind) || "artifact";
|
|
6490
|
+
const status = asString(record.status) || "unknown";
|
|
6491
|
+
const createdByJobId = asString(record.createdByJobId);
|
|
6492
|
+
const target = asRecord3(record.target);
|
|
6493
|
+
const metadata = asRecord3(record.metadata) || {};
|
|
6494
|
+
const subArtifactIds = Array.isArray(record.subArtifactIds) ? record.subArtifactIds.filter(
|
|
6495
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
6496
|
+
).slice(0, 8) : [];
|
|
6497
|
+
const relationships = compactJson(record.relationships, 220);
|
|
6498
|
+
const pieces = [
|
|
6499
|
+
`kind=${kind}`,
|
|
6500
|
+
`status=${status}`,
|
|
6501
|
+
createdByJobId ? `createdByJob=${createdByJobId}` : null,
|
|
6502
|
+
target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
|
|
6503
|
+
artifactStatePathSummary(metadata),
|
|
6504
|
+
artifactExecutionSummary(metadata),
|
|
6505
|
+
artifactIssueSummary(record),
|
|
6506
|
+
latestInputEditSummary(metadata),
|
|
6507
|
+
subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
|
|
6508
|
+
relationships ? `relationships=${relationships}` : null
|
|
6509
|
+
].filter(Boolean);
|
|
6510
|
+
return `- ${artifactId}: ${label}${pieces.length ? `; ${pieces.join("; ")}` : ""}`;
|
|
6511
|
+
}
|
|
6512
|
+
function buildArtifactHistory(show, artifactsById) {
|
|
6374
6513
|
if (!show) return void 0;
|
|
6375
|
-
|
|
6514
|
+
const artifactIds = show.sessionArtifactIds || [];
|
|
6515
|
+
const actionSuggestions = show.actionSuggestions || [];
|
|
6516
|
+
if (artifactIds.length === 0 && actionSuggestions.length === 0) {
|
|
6517
|
+
return `[Agent message]
|
|
6376
6518
|
${stringifyTranscriptValue({ show }, "")}`;
|
|
6519
|
+
}
|
|
6520
|
+
const lines = artifactIds.slice(0, 8).map(
|
|
6521
|
+
(artifactId) => artifactSummaryLine(artifactId, artifactsById?.[artifactId])
|
|
6522
|
+
);
|
|
6523
|
+
if (artifactIds.length > 8) {
|
|
6524
|
+
lines.push(`- ${artifactIds.length - 8} more artifacts omitted`);
|
|
6525
|
+
}
|
|
6526
|
+
if (actionSuggestions.length > 0) {
|
|
6527
|
+
if (artifactIds.length > 0) lines.push("[Agent suggested actions]");
|
|
6528
|
+
for (const suggestion of actionSuggestions.slice(0, 8)) {
|
|
6529
|
+
lines.push(
|
|
6530
|
+
`- ${suggestion.label}${suggestion.description ? `; ${suggestion.description}` : ""}`
|
|
6531
|
+
);
|
|
6532
|
+
}
|
|
6533
|
+
if (actionSuggestions.length > 8) {
|
|
6534
|
+
lines.push(`- ${actionSuggestions.length - 8} more suggestions omitted`);
|
|
6535
|
+
}
|
|
6536
|
+
}
|
|
6537
|
+
const otherRefs = {
|
|
6538
|
+
entryPaths: show.entryPaths,
|
|
6539
|
+
listNames: show.listNames,
|
|
6540
|
+
variableNames: show.variableNames,
|
|
6541
|
+
fileIds: show.fileIds
|
|
6542
|
+
};
|
|
6543
|
+
const hasOtherRefs = Object.values(otherRefs).some(
|
|
6544
|
+
(value) => Array.isArray(value) && value.length > 0
|
|
6545
|
+
);
|
|
6546
|
+
const title = artifactIds.length > 0 ? "[Agent displayed session artifacts]" : "[Agent suggested actions]";
|
|
6547
|
+
return [
|
|
6548
|
+
title,
|
|
6549
|
+
...lines,
|
|
6550
|
+
hasOtherRefs ? `Other shown refs: ${stringifyTranscriptValue(otherRefs, "")}` : null
|
|
6551
|
+
].filter(Boolean).join("\n");
|
|
6377
6552
|
}
|
|
6378
|
-
function normalizeConversationMessage(raw) {
|
|
6553
|
+
function normalizeConversationMessage(raw, artifactsById) {
|
|
6379
6554
|
const record = asRecord3(raw);
|
|
6380
6555
|
if (!record) return null;
|
|
6381
6556
|
const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
|
|
@@ -6387,6 +6562,12 @@ function normalizeConversationMessage(raw) {
|
|
|
6387
6562
|
const id = asString(record.id) || crypto.randomUUID();
|
|
6388
6563
|
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
6389
6564
|
if (!content && !show) return null;
|
|
6565
|
+
const artifactHistory = buildArtifactHistory(show, artifactsById);
|
|
6566
|
+
const historyContent = role === "assistant" ? content && artifactHistory ? `[Assistant reply]
|
|
6567
|
+
${content}
|
|
6568
|
+
|
|
6569
|
+
${artifactHistory}` : content ? `[Assistant reply]
|
|
6570
|
+
${content}` : artifactHistory : void 0;
|
|
6390
6571
|
return {
|
|
6391
6572
|
id,
|
|
6392
6573
|
role,
|
|
@@ -6395,8 +6576,7 @@ function normalizeConversationMessage(raw) {
|
|
|
6395
6576
|
jobId: asString(record.jobId),
|
|
6396
6577
|
promptId: asString(record.promptId),
|
|
6397
6578
|
show,
|
|
6398
|
-
historyContent
|
|
6399
|
-
${content}` : buildArtifactHistory(show) : void 0,
|
|
6579
|
+
historyContent,
|
|
6400
6580
|
source: "conversation"
|
|
6401
6581
|
};
|
|
6402
6582
|
}
|
|
@@ -6439,7 +6619,7 @@ ${assistantContent}`,
|
|
|
6439
6619
|
return entries;
|
|
6440
6620
|
});
|
|
6441
6621
|
}
|
|
6442
|
-
function normalizeAgentMessageEntries(jobId, rawMessages) {
|
|
6622
|
+
function normalizeAgentMessageEntries(jobId, rawMessages, artifactsById) {
|
|
6443
6623
|
return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
6444
6624
|
(left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
|
|
6445
6625
|
).flatMap((message) => {
|
|
@@ -6470,14 +6650,14 @@ ${reply}`,
|
|
|
6470
6650
|
timestamp,
|
|
6471
6651
|
jobId,
|
|
6472
6652
|
show,
|
|
6473
|
-
historyContent: buildArtifactHistory(show),
|
|
6653
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6474
6654
|
source: "job_agent_message"
|
|
6475
6655
|
});
|
|
6476
6656
|
}
|
|
6477
6657
|
return entries;
|
|
6478
6658
|
});
|
|
6479
6659
|
}
|
|
6480
|
-
function buildJobFallbackEntries(jobId, job, sessionHeap) {
|
|
6660
|
+
function buildJobFallbackEntries(jobId, job, sessionHeap, artifactsById) {
|
|
6481
6661
|
const timestamp = asNumber(job.finishedAt) || asNumber(job.startedAt) || asNumber(job.submittedAt) || 0;
|
|
6482
6662
|
const resultPreview = stringifyTranscriptValue(
|
|
6483
6663
|
job.result,
|
|
@@ -6515,7 +6695,7 @@ ${responseText}`,
|
|
|
6515
6695
|
timestamp,
|
|
6516
6696
|
jobId,
|
|
6517
6697
|
show,
|
|
6518
|
-
historyContent: buildArtifactHistory(show),
|
|
6698
|
+
historyContent: buildArtifactHistory(show, artifactsById),
|
|
6519
6699
|
source: "job_result"
|
|
6520
6700
|
});
|
|
6521
6701
|
}
|
|
@@ -6569,10 +6749,11 @@ function buildJobCodeEntry(jobId, job) {
|
|
|
6569
6749
|
function buildSessionTranscript(input) {
|
|
6570
6750
|
const liveDoc = input.liveDoc || null;
|
|
6571
6751
|
const sessionHeap = input.sessionHeap || EMPTY_HEAP;
|
|
6752
|
+
const artifactsById = artifactRecordsById(liveDoc);
|
|
6572
6753
|
const transcript = [];
|
|
6573
6754
|
const conversationMessages = asArray(
|
|
6574
6755
|
asRecord3(liveDoc?.conversation)?.messages
|
|
6575
|
-
).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
|
|
6756
|
+
).map((message) => normalizeConversationMessage(message, artifactsById)).filter((message) => Boolean(message));
|
|
6576
6757
|
const conversationPromptIds = new Set(
|
|
6577
6758
|
conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
|
|
6578
6759
|
);
|
|
@@ -6599,7 +6780,8 @@ function buildSessionTranscript(input) {
|
|
|
6599
6780
|
if (!assistantConversationJobIds.has(jobId)) {
|
|
6600
6781
|
const agentEntries = normalizeAgentMessageEntries(
|
|
6601
6782
|
jobId,
|
|
6602
|
-
job.agentMessages
|
|
6783
|
+
job.agentMessages,
|
|
6784
|
+
artifactsById
|
|
6603
6785
|
);
|
|
6604
6786
|
if (agentEntries.length > 0) {
|
|
6605
6787
|
transcript.push(...agentEntries);
|
|
@@ -6608,7 +6790,8 @@ function buildSessionTranscript(input) {
|
|
|
6608
6790
|
...buildJobFallbackEntries(
|
|
6609
6791
|
jobId,
|
|
6610
6792
|
job,
|
|
6611
|
-
sessionHeap
|
|
6793
|
+
sessionHeap,
|
|
6794
|
+
artifactsById
|
|
6612
6795
|
)
|
|
6613
6796
|
);
|
|
6614
6797
|
}
|
|
@@ -10774,16 +10957,107 @@ var StateMachineStateSchema = external_exports.union([
|
|
|
10774
10957
|
external_exports.string(),
|
|
10775
10958
|
external_exports.object({
|
|
10776
10959
|
name: external_exports.string().min(1),
|
|
10960
|
+
label: external_exports.string().optional(),
|
|
10961
|
+
description: external_exports.string().optional(),
|
|
10777
10962
|
isFinal: external_exports.boolean().optional()
|
|
10778
10963
|
}).strict()
|
|
10779
10964
|
]);
|
|
10965
|
+
var StateTransitionInputBindingSchema = external_exports.lazy(
|
|
10966
|
+
() => external_exports.union([
|
|
10967
|
+
external_exports.null(),
|
|
10968
|
+
external_exports.string(),
|
|
10969
|
+
external_exports.number(),
|
|
10970
|
+
external_exports.boolean(),
|
|
10971
|
+
external_exports.array(StateTransitionInputBindingSchema),
|
|
10972
|
+
external_exports.object({
|
|
10973
|
+
const: external_exports.unknown()
|
|
10974
|
+
}).strict(),
|
|
10975
|
+
external_exports.object({
|
|
10976
|
+
from: external_exports.literal("object"),
|
|
10977
|
+
path: external_exports.string().min(1),
|
|
10978
|
+
editable: external_exports.boolean().optional()
|
|
10979
|
+
}).strict(),
|
|
10980
|
+
external_exports.object({
|
|
10981
|
+
from: external_exports.literal("field"),
|
|
10982
|
+
name: external_exports.string().min(1),
|
|
10983
|
+
editable: external_exports.boolean().optional()
|
|
10984
|
+
}).strict(),
|
|
10985
|
+
external_exports.object({
|
|
10986
|
+
from: external_exports.literal("relationship"),
|
|
10987
|
+
name: external_exports.string().min(1),
|
|
10988
|
+
path: external_exports.string().min(1).optional(),
|
|
10989
|
+
many: external_exports.boolean().optional(),
|
|
10990
|
+
editable: external_exports.boolean().optional()
|
|
10991
|
+
}).strict(),
|
|
10992
|
+
external_exports.object({
|
|
10993
|
+
from: external_exports.literal("session"),
|
|
10994
|
+
path: external_exports.string().min(1),
|
|
10995
|
+
editable: external_exports.boolean().optional()
|
|
10996
|
+
}).strict(),
|
|
10997
|
+
external_exports.object({
|
|
10998
|
+
from: external_exports.literal("actor"),
|
|
10999
|
+
path: external_exports.string().min(1),
|
|
11000
|
+
editable: external_exports.boolean().optional()
|
|
11001
|
+
}).strict(),
|
|
11002
|
+
external_exports.record(external_exports.string(), StateTransitionInputBindingSchema)
|
|
11003
|
+
])
|
|
11004
|
+
);
|
|
11005
|
+
var StateTransitionActionSchema = external_exports.object({
|
|
11006
|
+
effect: external_exports.string().min(1),
|
|
11007
|
+
input: external_exports.record(external_exports.string(), StateTransitionInputBindingSchema).optional()
|
|
11008
|
+
}).strict();
|
|
11009
|
+
var StateTransitionAssigneeSchema = external_exports.object({
|
|
11010
|
+
kind: external_exports.string().min(1),
|
|
11011
|
+
from: StateTransitionInputBindingSchema.optional(),
|
|
11012
|
+
role: external_exports.string().optional(),
|
|
11013
|
+
label: external_exports.string().optional()
|
|
11014
|
+
}).strict();
|
|
11015
|
+
var StateTransitionRelatedStateRequirementSchema = external_exports.object({
|
|
11016
|
+
relationship: external_exports.string().min(1),
|
|
11017
|
+
machine: external_exports.string().min(1),
|
|
11018
|
+
state: external_exports.string().min(1),
|
|
11019
|
+
className: external_exports.string().min(1).optional(),
|
|
11020
|
+
label: external_exports.string().optional(),
|
|
11021
|
+
mode: external_exports.enum(["every", "some", "any"]).optional()
|
|
11022
|
+
}).strict();
|
|
11023
|
+
var StateTransitionRequirementsSchema = external_exports.object({
|
|
11024
|
+
fields: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11025
|
+
relationships: external_exports.array(external_exports.string().min(1)).optional(),
|
|
11026
|
+
relatedStates: external_exports.array(StateTransitionRelatedStateRequirementSchema).optional()
|
|
11027
|
+
}).strict();
|
|
11028
|
+
var StateTransitionPermissionSchema = external_exports.union([
|
|
11029
|
+
external_exports.string().min(1),
|
|
11030
|
+
external_exports.object({
|
|
11031
|
+
profile: external_exports.string().min(1).optional(),
|
|
11032
|
+
profileId: external_exports.string().min(1).optional(),
|
|
11033
|
+
label: external_exports.string().optional(),
|
|
11034
|
+
reason: external_exports.string().optional()
|
|
11035
|
+
}).strict()
|
|
11036
|
+
]);
|
|
11037
|
+
var StateTransitionExpectedOutcomeSchema = external_exports.union([
|
|
11038
|
+
external_exports.string().min(1),
|
|
11039
|
+
external_exports.object({
|
|
11040
|
+
machine: external_exports.string().min(1).optional(),
|
|
11041
|
+
state: external_exports.string().min(1),
|
|
11042
|
+
summary: external_exports.string().optional()
|
|
11043
|
+
}).strict()
|
|
11044
|
+
]);
|
|
10780
11045
|
var StateMachineTransitionSchema = external_exports.object({
|
|
10781
11046
|
name: external_exports.string().min(1),
|
|
10782
11047
|
from: external_exports.string().min(1),
|
|
10783
|
-
to: external_exports.string().min(1)
|
|
11048
|
+
to: external_exports.string().min(1),
|
|
11049
|
+
label: external_exports.string().optional(),
|
|
11050
|
+
description: external_exports.string().optional(),
|
|
11051
|
+
action: StateTransitionActionSchema.optional(),
|
|
11052
|
+
assignee: StateTransitionAssigneeSchema.optional(),
|
|
11053
|
+
requirements: StateTransitionRequirementsSchema.optional(),
|
|
11054
|
+
permission: StateTransitionPermissionSchema.optional(),
|
|
11055
|
+
risk: external_exports.enum(["low", "medium", "high"]).optional(),
|
|
11056
|
+
expectedOutcome: StateTransitionExpectedOutcomeSchema.optional()
|
|
10784
11057
|
}).strict();
|
|
10785
11058
|
external_exports.object({
|
|
10786
11059
|
name: external_exports.string().min(1),
|
|
11060
|
+
stateField: external_exports.string().min(1).optional(),
|
|
10787
11061
|
entryState: external_exports.string().min(1),
|
|
10788
11062
|
states: external_exports.array(StateMachineStateSchema).min(1),
|
|
10789
11063
|
transitions: external_exports.array(StateMachineTransitionSchema),
|
|
@@ -10850,6 +11124,16 @@ var PoliciesSchema = external_exports.object({
|
|
|
10850
11124
|
confirmWhen: external_exports.array(PolicyRuleSchema).optional(),
|
|
10851
11125
|
denyWhen: external_exports.array(PolicyRuleSchema).optional()
|
|
10852
11126
|
}).strict();
|
|
11127
|
+
var CreatesSchema = external_exports.union([
|
|
11128
|
+
external_exports.string().min(1),
|
|
11129
|
+
external_exports.object({
|
|
11130
|
+
className: external_exports.string().min(1),
|
|
11131
|
+
idPath: external_exports.string().min(1).optional(),
|
|
11132
|
+
pathPath: external_exports.string().min(1).optional(),
|
|
11133
|
+
statePath: external_exports.string().min(1).optional(),
|
|
11134
|
+
classStateHandle: external_exports.boolean().optional()
|
|
11135
|
+
}).strict()
|
|
11136
|
+
]);
|
|
10853
11137
|
external_exports.object({
|
|
10854
11138
|
postCondition: external_exports.union([
|
|
10855
11139
|
external_exports.string(),
|
|
@@ -10880,6 +11164,7 @@ external_exports.object({
|
|
|
10880
11164
|
mode: external_exports.string().optional()
|
|
10881
11165
|
}).strict()
|
|
10882
11166
|
]).optional(),
|
|
11167
|
+
creates: CreatesSchema.optional(),
|
|
10883
11168
|
access: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10884
11169
|
effectKind: external_exports.enum(["read", "write", "ui"]).optional(),
|
|
10885
11170
|
sideEffect: external_exports.enum(["read", "write", "ui", "readonly", "read_only"]).optional(),
|
|
@@ -11107,9 +11392,10 @@ function mergeMethodSummaryPatch(target, patch) {
|
|
|
11107
11392
|
if (patch.metamodels !== void 0) target.metamodels = patch.metamodels;
|
|
11108
11393
|
if (patch.effectBehaviors !== void 0)
|
|
11109
11394
|
target.effectBehaviors = patch.effectBehaviors;
|
|
11395
|
+
if (patch.creates !== void 0) target.creates = patch.creates;
|
|
11110
11396
|
if (patch.static !== void 0) target.static = patch.static;
|
|
11111
11397
|
}
|
|
11112
|
-
function
|
|
11398
|
+
function toPascalCase2(value) {
|
|
11113
11399
|
return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
11114
11400
|
}
|
|
11115
11401
|
function normalizeNotesInput(input) {
|
|
@@ -11167,29 +11453,60 @@ function normalizeEffectBehaviorSummary(metamodels) {
|
|
|
11167
11453
|
}
|
|
11168
11454
|
return Object.keys(result).length > 0 ? result : null;
|
|
11169
11455
|
}
|
|
11170
|
-
function
|
|
11171
|
-
if (!
|
|
11172
|
-
|
|
11456
|
+
function normalizeCreationSummary(metamodels) {
|
|
11457
|
+
if (!isObject(metamodels)) return null;
|
|
11458
|
+
let raw = metamodels.creates;
|
|
11459
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11460
|
+
const trimmed = raw.trim();
|
|
11461
|
+
if (trimmed.startsWith("{") || trimmed.startsWith('"')) {
|
|
11462
|
+
try {
|
|
11463
|
+
raw = JSON.parse(trimmed);
|
|
11464
|
+
} catch {
|
|
11465
|
+
return { className: trimmed };
|
|
11466
|
+
}
|
|
11467
|
+
} else {
|
|
11468
|
+
return { className: trimmed };
|
|
11469
|
+
}
|
|
11470
|
+
}
|
|
11471
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11472
|
+
return { className: raw.trim() };
|
|
11173
11473
|
}
|
|
11474
|
+
if (!isObject(raw)) return null;
|
|
11475
|
+
const className = typeof raw.className === "string" && raw.className.trim() ? raw.className.trim() : "";
|
|
11476
|
+
if (!className) return null;
|
|
11477
|
+
return {
|
|
11478
|
+
className,
|
|
11479
|
+
...typeof raw.idPath === "string" && raw.idPath.trim() ? { idPath: raw.idPath.trim() } : {},
|
|
11480
|
+
...typeof raw.pathPath === "string" && raw.pathPath.trim() ? { pathPath: raw.pathPath.trim() } : {},
|
|
11481
|
+
...typeof raw.statePath === "string" && raw.statePath.trim() ? { statePath: raw.statePath.trim() } : {},
|
|
11482
|
+
...typeof raw.classStateHandle === "boolean" ? { classStateHandle: raw.classStateHandle } : {}
|
|
11483
|
+
};
|
|
11484
|
+
}
|
|
11485
|
+
function buildEffectBehaviorDocs(effectBehaviors, creates) {
|
|
11174
11486
|
const docs = [];
|
|
11175
|
-
if (
|
|
11487
|
+
if (creates) {
|
|
11488
|
+
docs.push(
|
|
11489
|
+
`Creation method: creates ${creates.className}. The agent may use generated class-level new-record action methods for this class.`
|
|
11490
|
+
);
|
|
11491
|
+
}
|
|
11492
|
+
if (effectBehaviors?.approvalRequired?.required) {
|
|
11176
11493
|
docs.push(
|
|
11177
11494
|
effectBehaviors.approvalRequired.reason ? `Approval required: ${effectBehaviors.approvalRequired.reason}.` : "Approval required before execution."
|
|
11178
11495
|
);
|
|
11179
11496
|
}
|
|
11180
|
-
if (effectBehaviors
|
|
11497
|
+
if (effectBehaviors?.postCondition) {
|
|
11181
11498
|
docs.push(`Post-condition: ${effectBehaviors.postCondition.condition}.`);
|
|
11182
11499
|
if (effectBehaviors.postCondition.description) {
|
|
11183
11500
|
docs.push(effectBehaviors.postCondition.description);
|
|
11184
11501
|
}
|
|
11185
11502
|
}
|
|
11186
|
-
if (effectBehaviors
|
|
11503
|
+
if (effectBehaviors?.dryRun?.enabled) {
|
|
11187
11504
|
docs.push("Supports dry run.");
|
|
11188
11505
|
if (effectBehaviors.dryRun.description) {
|
|
11189
11506
|
docs.push(effectBehaviors.dryRun.description);
|
|
11190
11507
|
}
|
|
11191
11508
|
}
|
|
11192
|
-
if (effectBehaviors
|
|
11509
|
+
if (effectBehaviors?.reverse) {
|
|
11193
11510
|
if (effectBehaviors.reverse.handler) {
|
|
11194
11511
|
docs.push(`Reverse handler: ${effectBehaviors.reverse.handler}.`);
|
|
11195
11512
|
} else {
|
|
@@ -11248,13 +11565,21 @@ function buildEffectBehaviorMutations(toolPath, spec) {
|
|
|
11248
11565
|
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { set_approval_required(${args}) { kind } } }`
|
|
11249
11566
|
});
|
|
11250
11567
|
}
|
|
11568
|
+
if (spec.creates !== void 0) {
|
|
11569
|
+
mutations.push({
|
|
11570
|
+
label: `set creates on ${toolPath}`,
|
|
11571
|
+
query: `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "creates", label: "creates") { set_string_value(value: ${JSON.stringify(
|
|
11572
|
+
JSON.stringify(spec.creates)
|
|
11573
|
+
)}) { done } } } }`
|
|
11574
|
+
});
|
|
11575
|
+
}
|
|
11251
11576
|
return mutations;
|
|
11252
11577
|
}
|
|
11253
11578
|
function readMethodEffectBehaviors(rawMethod) {
|
|
11579
|
+
const metamodels = isObject(rawMethod.metamodels) ? rawMethod.metamodels : null;
|
|
11254
11580
|
return {
|
|
11255
|
-
effectBehaviors: normalizeEffectBehaviorSummary(
|
|
11256
|
-
|
|
11257
|
-
)
|
|
11581
|
+
effectBehaviors: normalizeEffectBehaviorSummary(metamodels),
|
|
11582
|
+
creates: normalizeCreationSummary(metamodels)
|
|
11258
11583
|
};
|
|
11259
11584
|
}
|
|
11260
11585
|
var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
@@ -11276,6 +11601,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11276
11601
|
{
|
|
11277
11602
|
key: "approvalRequired",
|
|
11278
11603
|
description: "Boolean or `{ required, reason, mode }`."
|
|
11604
|
+
},
|
|
11605
|
+
{
|
|
11606
|
+
key: "creates",
|
|
11607
|
+
description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, classStateHandle }`.'
|
|
11279
11608
|
}
|
|
11280
11609
|
]
|
|
11281
11610
|
},
|
|
@@ -11395,7 +11724,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
|
|
|
11395
11724
|
...methodIR,
|
|
11396
11725
|
docs: [
|
|
11397
11726
|
...methodIR.docs,
|
|
11398
|
-
...buildEffectBehaviorDocs(
|
|
11727
|
+
...buildEffectBehaviorDocs(
|
|
11728
|
+
methodSummary.effectBehaviors,
|
|
11729
|
+
methodSummary.creates
|
|
11730
|
+
)
|
|
11399
11731
|
]
|
|
11400
11732
|
};
|
|
11401
11733
|
}
|
|
@@ -11636,15 +11968,50 @@ function toRecordSearchResult(className, node) {
|
|
|
11636
11968
|
return [];
|
|
11637
11969
|
}
|
|
11638
11970
|
) : [];
|
|
11971
|
+
const graphPathId = extractRecordIdFromGraphPath(path2, className);
|
|
11972
|
+
const realIdField = fields.find(
|
|
11973
|
+
(field) => normalizeGraphPathSegment(field.name) === "real_id" && typeof field.value === "string" && field.value.trim()
|
|
11974
|
+
);
|
|
11975
|
+
const id = typeof realIdField?.value === "string" ? realIdField.value.trim() : graphPathId;
|
|
11976
|
+
const rawLabel = typeof node.label === "string" && node.label.trim() ? node.label : "";
|
|
11977
|
+
if (fields.length === 0 && rawLabel && isPlaceholderRecordLabel(rawLabel, graphPathId, path2)) {
|
|
11978
|
+
return null;
|
|
11979
|
+
}
|
|
11980
|
+
const fallbackLabel = displayLabelFromFields(fields);
|
|
11981
|
+
const label = rawLabel && !isPlaceholderRecordLabel(rawLabel, id, path2) ? rawLabel : fallbackLabel || rawLabel || id;
|
|
11639
11982
|
return {
|
|
11640
11983
|
path: path2,
|
|
11641
11984
|
className,
|
|
11642
|
-
id
|
|
11643
|
-
label
|
|
11985
|
+
id,
|
|
11986
|
+
label,
|
|
11644
11987
|
description: typeof node.description === "string" && node.description.trim() ? node.description : null,
|
|
11645
11988
|
fields
|
|
11646
11989
|
};
|
|
11647
11990
|
}
|
|
11991
|
+
function isPlaceholderRecordLabel(label, id, path2) {
|
|
11992
|
+
const normalizedLabel = normalizeGraphPathSegment(label);
|
|
11993
|
+
return normalizedLabel === normalizeGraphPathSegment(id) || normalizedLabel === normalizeGraphPathSegment(path2);
|
|
11994
|
+
}
|
|
11995
|
+
function displayLabelFromFields(fields) {
|
|
11996
|
+
const preferredFieldNames = [
|
|
11997
|
+
"name",
|
|
11998
|
+
"title",
|
|
11999
|
+
"label",
|
|
12000
|
+
"display_name",
|
|
12001
|
+
"file_name",
|
|
12002
|
+
"number",
|
|
12003
|
+
"code"
|
|
12004
|
+
];
|
|
12005
|
+
for (const preferred of preferredFieldNames) {
|
|
12006
|
+
const match = fields.find(
|
|
12007
|
+
(field) => normalizeGraphPathSegment(field.name) === preferred && typeof field.value === "string" && field.value.trim()
|
|
12008
|
+
);
|
|
12009
|
+
if (typeof match?.value === "string") {
|
|
12010
|
+
return match.value.trim();
|
|
12011
|
+
}
|
|
12012
|
+
}
|
|
12013
|
+
return null;
|
|
12014
|
+
}
|
|
11648
12015
|
function normalizeRecordSearchText(value) {
|
|
11649
12016
|
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
|
|
11650
12017
|
}
|
|
@@ -12544,15 +12911,47 @@ var searchableMetamodelPackage = defineMetamodelPackage({
|
|
|
12544
12911
|
|
|
12545
12912
|
// ../metamodel-state-machine/src/index.ts
|
|
12546
12913
|
function normalizeStateMachines(values) {
|
|
12914
|
+
const parseJsonRecord = (value) => {
|
|
12915
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
12916
|
+
return value;
|
|
12917
|
+
}
|
|
12918
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
12919
|
+
try {
|
|
12920
|
+
const parsed = JSON.parse(value);
|
|
12921
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
12922
|
+
} catch {
|
|
12923
|
+
return null;
|
|
12924
|
+
}
|
|
12925
|
+
};
|
|
12926
|
+
const parseJsonValue = (value) => {
|
|
12927
|
+
if (value === null || typeof value === "undefined") return null;
|
|
12928
|
+
if (typeof value !== "string") return value;
|
|
12929
|
+
if (!value.trim()) return null;
|
|
12930
|
+
try {
|
|
12931
|
+
return JSON.parse(value);
|
|
12932
|
+
} catch {
|
|
12933
|
+
return value;
|
|
12934
|
+
}
|
|
12935
|
+
};
|
|
12547
12936
|
return (values || []).map((machine) => {
|
|
12548
12937
|
const states = (machine?.states || []).map((state) => ({
|
|
12549
12938
|
name: String(state?.name || ""),
|
|
12550
|
-
|
|
12939
|
+
label: typeof state?.label === "string" ? state.label : null,
|
|
12940
|
+
description: typeof state?.description === "string" ? state.description : null,
|
|
12941
|
+
isFinal: Boolean(state?.is_final ?? state?.isFinal)
|
|
12551
12942
|
})).filter((state) => state.name.length > 0);
|
|
12552
12943
|
const transitions = (machine?.transitions || []).map((transition) => ({
|
|
12553
12944
|
name: String(transition?.name || ""),
|
|
12554
12945
|
from: String(transition?.from?.name || ""),
|
|
12555
|
-
to: String(transition?.to?.name || "")
|
|
12946
|
+
to: String(transition?.to?.name || ""),
|
|
12947
|
+
label: typeof transition?.label === "string" ? transition.label : null,
|
|
12948
|
+
description: typeof transition?.description === "string" ? transition.description : null,
|
|
12949
|
+
action: parseJsonRecord(transition?.action) || parseJsonRecord(transition?.action_json),
|
|
12950
|
+
assignee: parseJsonRecord(transition?.assignee) || parseJsonRecord(transition?.assignee_json),
|
|
12951
|
+
requirements: parseJsonRecord(transition?.requirements) || parseJsonRecord(transition?.requirements_json),
|
|
12952
|
+
permission: parseJsonValue(transition?.permission) ?? parseJsonValue(transition?.permission_json),
|
|
12953
|
+
risk: transition?.risk === "low" || transition?.risk === "medium" || transition?.risk === "high" ? transition.risk : null,
|
|
12954
|
+
expectedOutcome: parseJsonValue(transition?.expectedOutcome) ?? parseJsonValue(transition?.expected_outcome_json)
|
|
12556
12955
|
})).filter(
|
|
12557
12956
|
(transition) => transition.name.length > 0 && transition.from.length > 0 && transition.to.length > 0
|
|
12558
12957
|
);
|
|
@@ -12566,7 +12965,7 @@ function normalizeStateMachines(values) {
|
|
|
12566
12965
|
}).filter((machine) => machine.name.length > 0);
|
|
12567
12966
|
}
|
|
12568
12967
|
function stateTypeName(className, machineName) {
|
|
12569
|
-
return `${
|
|
12968
|
+
return `${toPascalCase2(className)}${toPascalCase2(machineName)}`;
|
|
12570
12969
|
}
|
|
12571
12970
|
function transitionTypeName(className, machineName) {
|
|
12572
12971
|
return `${stateTypeName(className, machineName)}Transition`;
|
|
@@ -12574,6 +12973,15 @@ function transitionTypeName(className, machineName) {
|
|
|
12574
12973
|
function pathTypeName(className, machineName) {
|
|
12575
12974
|
return `${stateTypeName(className, machineName)}Path`;
|
|
12576
12975
|
}
|
|
12976
|
+
function methodToken(value) {
|
|
12977
|
+
const token = String(value || "").trim().replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
12978
|
+
return token || "state";
|
|
12979
|
+
}
|
|
12980
|
+
function transitionActionsForMachine(machine) {
|
|
12981
|
+
return Object.fromEntries(
|
|
12982
|
+
(machine.transitions || []).filter((transition) => transition.action?.effect).map((transition) => [transition.name, transition.action])
|
|
12983
|
+
);
|
|
12984
|
+
}
|
|
12577
12985
|
function normalizeStateDefinitions(machine) {
|
|
12578
12986
|
const finalStates = new Set(machine.finalStates || []);
|
|
12579
12987
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -12587,6 +12995,8 @@ function normalizeStateDefinitions(machine) {
|
|
|
12587
12995
|
}
|
|
12588
12996
|
states.set(rawState.name, {
|
|
12589
12997
|
name: rawState.name,
|
|
12998
|
+
label: rawState.label,
|
|
12999
|
+
description: rawState.description,
|
|
12590
13000
|
isFinal: Boolean(rawState.isFinal) || finalStates.has(rawState.name)
|
|
12591
13001
|
});
|
|
12592
13002
|
}
|
|
@@ -12598,6 +13008,44 @@ function normalizeStateDefinitions(machine) {
|
|
|
12598
13008
|
}
|
|
12599
13009
|
return [...states.values()];
|
|
12600
13010
|
}
|
|
13011
|
+
function transitionMetadataGraphqlArgs(transition) {
|
|
13012
|
+
const args = [];
|
|
13013
|
+
if (typeof transition.label === "string") {
|
|
13014
|
+
args.push(`label: ${JSON.stringify(transition.label)}`);
|
|
13015
|
+
}
|
|
13016
|
+
if (typeof transition.description === "string") {
|
|
13017
|
+
args.push(`description: ${JSON.stringify(transition.description)}`);
|
|
13018
|
+
}
|
|
13019
|
+
if (transition.action) {
|
|
13020
|
+
args.push(
|
|
13021
|
+
`action_json: ${JSON.stringify(JSON.stringify(transition.action))}`
|
|
13022
|
+
);
|
|
13023
|
+
}
|
|
13024
|
+
if (transition.assignee) {
|
|
13025
|
+
args.push(
|
|
13026
|
+
`assignee_json: ${JSON.stringify(JSON.stringify(transition.assignee))}`
|
|
13027
|
+
);
|
|
13028
|
+
}
|
|
13029
|
+
if (transition.requirements) {
|
|
13030
|
+
args.push(
|
|
13031
|
+
`requirements_json: ${JSON.stringify(JSON.stringify(transition.requirements))}`
|
|
13032
|
+
);
|
|
13033
|
+
}
|
|
13034
|
+
if (transition.permission) {
|
|
13035
|
+
args.push(
|
|
13036
|
+
`permission_json: ${JSON.stringify(JSON.stringify(transition.permission))}`
|
|
13037
|
+
);
|
|
13038
|
+
}
|
|
13039
|
+
if (transition.risk) {
|
|
13040
|
+
args.push(`risk: ${JSON.stringify(transition.risk)}`);
|
|
13041
|
+
}
|
|
13042
|
+
if (transition.expectedOutcome) {
|
|
13043
|
+
args.push(
|
|
13044
|
+
`expected_outcome_json: ${JSON.stringify(JSON.stringify(transition.expectedOutcome))}`
|
|
13045
|
+
);
|
|
13046
|
+
}
|
|
13047
|
+
return args.length > 0 ? `, ${args.join(", ")}` : "";
|
|
13048
|
+
}
|
|
12601
13049
|
function buildStateMachineModelMutations(modelPath, machines) {
|
|
12602
13050
|
const mutations = [];
|
|
12603
13051
|
for (const machine of machines || []) {
|
|
@@ -12608,12 +13056,13 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12608
13056
|
)}, entry_state: ${JSON.stringify(machine.entryState)}) { name } } }`
|
|
12609
13057
|
});
|
|
12610
13058
|
for (const state of normalizeStateDefinitions(machine)) {
|
|
12611
|
-
if (state.name === machine.entryState && !state.isFinal)
|
|
13059
|
+
if (state.name === machine.entryState && !state.isFinal && !state.label && !state.description)
|
|
13060
|
+
continue;
|
|
12612
13061
|
mutations.push({
|
|
12613
13062
|
label: `add state ${state.name} on ${modelPath}.${machine.name}`,
|
|
12614
13063
|
query: `mutation { at(path: ${JSON.stringify(modelPath)}) { state_machine(name: ${JSON.stringify(
|
|
12615
13064
|
machine.name
|
|
12616
|
-
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}) { name } } } }`
|
|
13065
|
+
)}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}, label: ${JSON.stringify(state.label || null)}, description: ${JSON.stringify(state.description || null)}) { name } } } }`
|
|
12617
13066
|
});
|
|
12618
13067
|
}
|
|
12619
13068
|
for (const transition of machine.transitions || []) {
|
|
@@ -12625,7 +13074,7 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
12625
13074
|
transition.name
|
|
12626
13075
|
)}, from: ${JSON.stringify(transition.from)}, to: ${JSON.stringify(
|
|
12627
13076
|
transition.to
|
|
12628
|
-
)}) { name } } } }`
|
|
13077
|
+
)}${transitionMetadataGraphqlArgs(transition)}) { name } } } }`
|
|
12629
13078
|
});
|
|
12630
13079
|
}
|
|
12631
13080
|
}
|
|
@@ -12652,7 +13101,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12652
13101
|
const transitionName = transitionTypeName(classSummary.name, machine.name);
|
|
12653
13102
|
pathTypeName(classSummary.name, machine.name);
|
|
12654
13103
|
const docsPrefix = `${classSummary.name}.${machine.name}`;
|
|
12655
|
-
|
|
13104
|
+
const methods = [
|
|
12656
13105
|
{
|
|
12657
13106
|
name: `get_${machine.name}`,
|
|
12658
13107
|
docs: [`Get the current ${docsPrefix} state.`],
|
|
@@ -12675,7 +13124,7 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12675
13124
|
],
|
|
12676
13125
|
static: false,
|
|
12677
13126
|
params: [{ name: "target", type: stateName }],
|
|
12678
|
-
returnType: `Promise<${
|
|
13127
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
12679
13128
|
runtime: {
|
|
12680
13129
|
kind: "state_machine",
|
|
12681
13130
|
machineName: machine.name,
|
|
@@ -12748,6 +13197,99 @@ function buildMachineMethods(classSummary, machine) {
|
|
|
12748
13197
|
}
|
|
12749
13198
|
}
|
|
12750
13199
|
];
|
|
13200
|
+
const creationMethods = (classSummary.methods || []).filter(
|
|
13201
|
+
(method) => method.static === true && Boolean(method.creates) && method.creates?.className === classSummary.name && typeof method.effectKey === "string" && method.effectKey.length > 0
|
|
13202
|
+
);
|
|
13203
|
+
for (const state of machine.states) {
|
|
13204
|
+
const stateNameValue = typeof state === "string" ? state : String(state?.name || "");
|
|
13205
|
+
if (!stateNameValue) continue;
|
|
13206
|
+
const token = methodToken(stateNameValue);
|
|
13207
|
+
methods.push(
|
|
13208
|
+
{
|
|
13209
|
+
name: `reach_${machine.name}_to_${token}`,
|
|
13210
|
+
docs: [`Reach ${docsPrefix} state ${stateNameValue}.`],
|
|
13211
|
+
static: false,
|
|
13212
|
+
params: [],
|
|
13213
|
+
returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
|
|
13214
|
+
runtime: {
|
|
13215
|
+
kind: "state_machine",
|
|
13216
|
+
machineName: machine.name,
|
|
13217
|
+
className: classSummary.name,
|
|
13218
|
+
stateTypeName: stateName,
|
|
13219
|
+
transitionTypeName: transitionName,
|
|
13220
|
+
operation: "reach",
|
|
13221
|
+
targetState: stateNameValue,
|
|
13222
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13223
|
+
}
|
|
13224
|
+
},
|
|
13225
|
+
{
|
|
13226
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13227
|
+
docs: [
|
|
13228
|
+
`Prepare a reviewable artifact that can move ${docsPrefix} to ${stateNameValue}.`
|
|
13229
|
+
],
|
|
13230
|
+
static: false,
|
|
13231
|
+
params: [],
|
|
13232
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13233
|
+
runtime: {
|
|
13234
|
+
kind: "state_machine",
|
|
13235
|
+
machineName: machine.name,
|
|
13236
|
+
className: classSummary.name,
|
|
13237
|
+
stateTypeName: stateName,
|
|
13238
|
+
transitionTypeName: transitionName,
|
|
13239
|
+
operation: "prepare_reach",
|
|
13240
|
+
targetState: stateNameValue,
|
|
13241
|
+
transitionActions: transitionActionsForMachine(machine)
|
|
13242
|
+
}
|
|
13243
|
+
}
|
|
13244
|
+
);
|
|
13245
|
+
for (const creationMethod of creationMethods) {
|
|
13246
|
+
const creationRuntime = {
|
|
13247
|
+
kind: "state_machine",
|
|
13248
|
+
machineName: machine.name,
|
|
13249
|
+
className: classSummary.name,
|
|
13250
|
+
stateTypeName: stateName,
|
|
13251
|
+
transitionTypeName: transitionName,
|
|
13252
|
+
operation: "prepare_create_reach",
|
|
13253
|
+
targetState: stateNameValue,
|
|
13254
|
+
transitionActions: transitionActionsForMachine(machine),
|
|
13255
|
+
creation: {
|
|
13256
|
+
methodName: creationMethod.name,
|
|
13257
|
+
effectKey: creationMethod.effectKey || creationMethod.name,
|
|
13258
|
+
inputSchema: creationMethod.inputSchema,
|
|
13259
|
+
outputSchema: creationMethod.outputSchema,
|
|
13260
|
+
creates: creationMethod.creates
|
|
13261
|
+
}
|
|
13262
|
+
};
|
|
13263
|
+
const viaName = `prepare_${machine.name}_to_${token}_via_${methodToken(creationMethod.name)}`;
|
|
13264
|
+
methods.push({
|
|
13265
|
+
name: viaName,
|
|
13266
|
+
docs: [
|
|
13267
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name} through ${creationMethod.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13268
|
+
],
|
|
13269
|
+
static: true,
|
|
13270
|
+
params: [
|
|
13271
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13272
|
+
],
|
|
13273
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13274
|
+
runtime: creationRuntime
|
|
13275
|
+
});
|
|
13276
|
+
if (creationMethods.length === 1) {
|
|
13277
|
+
methods.push({
|
|
13278
|
+
name: `prepare_${machine.name}_to_${token}`,
|
|
13279
|
+
docs: [
|
|
13280
|
+
`Prepare a reviewable artifact that will create a new ${classSummary.name}, then move ${docsPrefix} to ${stateNameValue}.`
|
|
13281
|
+
],
|
|
13282
|
+
static: true,
|
|
13283
|
+
params: [
|
|
13284
|
+
{ name: "input", type: "Record<string, any>", optional: true }
|
|
13285
|
+
],
|
|
13286
|
+
returnType: "Promise<SessionArtifactRecord>",
|
|
13287
|
+
runtime: creationRuntime
|
|
13288
|
+
});
|
|
13289
|
+
}
|
|
13290
|
+
}
|
|
13291
|
+
}
|
|
13292
|
+
return methods;
|
|
12751
13293
|
}
|
|
12752
13294
|
function readStateMachineSummaries(rawClass) {
|
|
12753
13295
|
return {
|
|
@@ -12770,8 +13312,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12770
13312
|
type StateMachineMutation {
|
|
12771
13313
|
name: String!
|
|
12772
13314
|
state_machine: StateMachine!
|
|
12773
|
-
add_state(name: String!, is_final: Boolean): StateMachineMutation!
|
|
12774
|
-
add_transition(name: String!, from: String!, to: String
|
|
13315
|
+
add_state(name: String!, is_final: Boolean, label: String, description: String): StateMachineMutation!
|
|
13316
|
+
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!
|
|
12775
13317
|
activate_transition(name: String!): StateMachineMutation!
|
|
12776
13318
|
}
|
|
12777
13319
|
|
|
@@ -12788,6 +13330,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12788
13330
|
type StateMachineSnapshotMutation {
|
|
12789
13331
|
snapshot: StateMachineSnapshot!
|
|
12790
13332
|
activate_transition(name: String!): StateMachineSnapshotMutation!
|
|
13333
|
+
observe_state(state: String!, force: Boolean, source: String): StateMachineSnapshotMutation!
|
|
12791
13334
|
}
|
|
12792
13335
|
|
|
12793
13336
|
type StateMachine {
|
|
@@ -12807,6 +13350,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12807
13350
|
|
|
12808
13351
|
type StateMachineState {
|
|
12809
13352
|
name: String!
|
|
13353
|
+
label: String
|
|
13354
|
+
description: String
|
|
12810
13355
|
is_final: Boolean!
|
|
12811
13356
|
}
|
|
12812
13357
|
|
|
@@ -12814,6 +13359,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12814
13359
|
name: String!
|
|
12815
13360
|
from: StateMachineState!
|
|
12816
13361
|
to: StateMachineState!
|
|
13362
|
+
label: String
|
|
13363
|
+
description: String
|
|
13364
|
+
action_json: String
|
|
13365
|
+
assignee_json: String
|
|
13366
|
+
requirements_json: String
|
|
13367
|
+
permission_json: String
|
|
13368
|
+
risk: String
|
|
13369
|
+
expected_outcome_json: String
|
|
12817
13370
|
}
|
|
12818
13371
|
|
|
12819
13372
|
type StateMachinePath {
|
|
@@ -12866,23 +13419,47 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12866
13419
|
StateMachineMutation: {
|
|
12867
13420
|
name: (value) => value.name,
|
|
12868
13421
|
state_machine: async (value) => await run(value.target.state_machine(value.name)),
|
|
12869
|
-
add_state: async (value, { name, is_final }) => {
|
|
13422
|
+
add_state: async (value, { name, is_final, label, description }) => {
|
|
12870
13423
|
await run(
|
|
12871
13424
|
value.target.add_state_machine_state(
|
|
12872
13425
|
value.name,
|
|
12873
13426
|
name,
|
|
12874
|
-
is_final ?? false
|
|
13427
|
+
is_final ?? false,
|
|
13428
|
+
label,
|
|
13429
|
+
description
|
|
12875
13430
|
)
|
|
12876
13431
|
);
|
|
12877
13432
|
return value;
|
|
12878
13433
|
},
|
|
12879
|
-
add_transition: async (value, {
|
|
13434
|
+
add_transition: async (value, {
|
|
13435
|
+
name,
|
|
13436
|
+
from,
|
|
13437
|
+
to,
|
|
13438
|
+
label,
|
|
13439
|
+
description,
|
|
13440
|
+
action_json,
|
|
13441
|
+
assignee_json,
|
|
13442
|
+
requirements_json,
|
|
13443
|
+
permission_json,
|
|
13444
|
+
risk,
|
|
13445
|
+
expected_outcome_json
|
|
13446
|
+
}) => {
|
|
12880
13447
|
await run(
|
|
12881
13448
|
value.target.add_state_machine_transition(
|
|
12882
13449
|
value.name,
|
|
12883
13450
|
name,
|
|
12884
13451
|
from,
|
|
12885
|
-
to
|
|
13452
|
+
to,
|
|
13453
|
+
{
|
|
13454
|
+
label,
|
|
13455
|
+
description,
|
|
13456
|
+
actionJson: action_json,
|
|
13457
|
+
assigneeJson: assignee_json,
|
|
13458
|
+
requirementsJson: requirements_json,
|
|
13459
|
+
permissionJson: permission_json,
|
|
13460
|
+
risk,
|
|
13461
|
+
expectedOutcomeJson: expected_outcome_json
|
|
13462
|
+
}
|
|
12886
13463
|
)
|
|
12887
13464
|
);
|
|
12888
13465
|
return value;
|
|
@@ -12901,16 +13478,37 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12901
13478
|
value.target.activate_state_machine_transition(value.name, name)
|
|
12902
13479
|
);
|
|
12903
13480
|
return value;
|
|
13481
|
+
},
|
|
13482
|
+
observe_state: async (value, { state, force, source }) => {
|
|
13483
|
+
await run(
|
|
13484
|
+
value.target.observe_state_machine_state(
|
|
13485
|
+
value.name,
|
|
13486
|
+
state,
|
|
13487
|
+
force === true,
|
|
13488
|
+
source
|
|
13489
|
+
)
|
|
13490
|
+
);
|
|
13491
|
+
return value;
|
|
12904
13492
|
}
|
|
12905
13493
|
},
|
|
12906
13494
|
StateMachineState: {
|
|
12907
13495
|
name: (value) => value.name,
|
|
13496
|
+
label: (value) => value.label || null,
|
|
13497
|
+
description: (value) => value.description || null,
|
|
12908
13498
|
is_final: (value) => value.is_final
|
|
12909
13499
|
},
|
|
12910
13500
|
StateMachineTransition: {
|
|
12911
13501
|
name: (value) => value.name,
|
|
12912
13502
|
from: (value) => value.from_state || { name: value.from, is_final: false },
|
|
12913
|
-
to: (value) => value.to_state || { name: value.to, is_final: false }
|
|
13503
|
+
to: (value) => value.to_state || { name: value.to, is_final: false },
|
|
13504
|
+
label: (value) => value.label || null,
|
|
13505
|
+
description: (value) => value.description || null,
|
|
13506
|
+
action_json: (value) => value.action_json || null,
|
|
13507
|
+
assignee_json: (value) => value.assignee_json || null,
|
|
13508
|
+
requirements_json: (value) => value.requirements_json || null,
|
|
13509
|
+
permission_json: (value) => value.permission_json || null,
|
|
13510
|
+
risk: (value) => value.risk || null,
|
|
13511
|
+
expected_outcome_json: (value) => value.expected_outcome_json || null
|
|
12914
13512
|
},
|
|
12915
13513
|
StateMachinePath: {
|
|
12916
13514
|
states: (value) => value.states,
|
|
@@ -12977,6 +13575,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
12977
13575
|
name
|
|
12978
13576
|
from { name }
|
|
12979
13577
|
to { name }
|
|
13578
|
+
label
|
|
13579
|
+
description
|
|
13580
|
+
action_json
|
|
13581
|
+
assignee_json
|
|
13582
|
+
requirements_json
|
|
13583
|
+
permission_json
|
|
13584
|
+
risk
|
|
13585
|
+
expected_outcome_json
|
|
12980
13586
|
}
|
|
12981
13587
|
}`
|
|
12982
13588
|
]
|
|
@@ -13230,6 +13836,26 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
13230
13836
|
var BUILTIN_MODULES = {
|
|
13231
13837
|
standard_modules: STANDARD_MODULES_OPERATIONS
|
|
13232
13838
|
};
|
|
13839
|
+
function stateNameFromMethodName(methodName) {
|
|
13840
|
+
const raw = methodName.startsWith("to") ? methodName.slice(2) : methodName;
|
|
13841
|
+
return raw.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
13842
|
+
}
|
|
13843
|
+
function appendQueryOptions(searchParams, query) {
|
|
13844
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
13845
|
+
if (value === null || typeof value === "undefined" || value === "") {
|
|
13846
|
+
continue;
|
|
13847
|
+
}
|
|
13848
|
+
if (value instanceof Date) {
|
|
13849
|
+
searchParams.set(key, value.toISOString());
|
|
13850
|
+
continue;
|
|
13851
|
+
}
|
|
13852
|
+
if (Array.isArray(value)) {
|
|
13853
|
+
if (value.length > 0) searchParams.set(key, value.join(","));
|
|
13854
|
+
continue;
|
|
13855
|
+
}
|
|
13856
|
+
searchParams.set(key, String(value));
|
|
13857
|
+
}
|
|
13858
|
+
}
|
|
13233
13859
|
var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
|
|
13234
13860
|
var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
|
|
13235
13861
|
var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
|
|
@@ -13260,8 +13886,20 @@ function bodyInitFromSessionFileUpload(body) {
|
|
|
13260
13886
|
return body;
|
|
13261
13887
|
}
|
|
13262
13888
|
var EFFECT_CATALOG_SYNC_TIMEOUT_MS = 12e4;
|
|
13889
|
+
var EFFECT_CATALOG_SYNC_BATCH_SIZE = 20;
|
|
13263
13890
|
var EFFECT_CATALOG_SYNC_RETRY_COUNT = 3;
|
|
13264
13891
|
var EFFECT_CATALOG_SYNC_RETRY_DELAY_MS = 1e3;
|
|
13892
|
+
function chunkItems(items, batchSize) {
|
|
13893
|
+
const chunks = [];
|
|
13894
|
+
for (let offset = 0; offset < items.length; offset += batchSize) {
|
|
13895
|
+
chunks.push(items.slice(offset, offset + batchSize));
|
|
13896
|
+
}
|
|
13897
|
+
return chunks;
|
|
13898
|
+
}
|
|
13899
|
+
function isUnsupportedEffectCatalogMutation(error) {
|
|
13900
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13901
|
+
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");
|
|
13902
|
+
}
|
|
13265
13903
|
function planRecordObjectsChunks(records, batchSize) {
|
|
13266
13904
|
const total = records.length;
|
|
13267
13905
|
const size = Math.max(1, Math.min(batchSize, total));
|
|
@@ -13273,6 +13911,23 @@ function planRecordObjectsChunks(records, batchSize) {
|
|
|
13273
13911
|
}
|
|
13274
13912
|
return plans;
|
|
13275
13913
|
}
|
|
13914
|
+
function preserveRecordObjectRealId(record) {
|
|
13915
|
+
const realId = record.id.trim();
|
|
13916
|
+
if (!realId) {
|
|
13917
|
+
return record;
|
|
13918
|
+
}
|
|
13919
|
+
const fields = record.fields || {};
|
|
13920
|
+
if (typeof fields.real_id === "string" && fields.real_id.trim()) {
|
|
13921
|
+
return record;
|
|
13922
|
+
}
|
|
13923
|
+
return {
|
|
13924
|
+
...record,
|
|
13925
|
+
fields: {
|
|
13926
|
+
...fields,
|
|
13927
|
+
real_id: realId
|
|
13928
|
+
}
|
|
13929
|
+
};
|
|
13930
|
+
}
|
|
13276
13931
|
function computeEffectKey2(effect) {
|
|
13277
13932
|
const attachedClass = effect.className?.trim();
|
|
13278
13933
|
if (!attachedClass) {
|
|
@@ -13510,11 +14165,105 @@ var Environment = class _Environment {
|
|
|
13510
14165
|
getAwaitingCount: async () => this.getAwaitingRecordCount()
|
|
13511
14166
|
};
|
|
13512
14167
|
}
|
|
14168
|
+
/**
|
|
14169
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14170
|
+
* own the customer application's state machine.
|
|
14171
|
+
*/
|
|
14172
|
+
async recordState(input) {
|
|
14173
|
+
const { machine, state, ...target } = input;
|
|
14174
|
+
if (!machine.trim()) {
|
|
14175
|
+
throw new Error("State update requires a machine name");
|
|
14176
|
+
}
|
|
14177
|
+
if (!state.trim()) {
|
|
14178
|
+
throw new Error("State update requires a state");
|
|
14179
|
+
}
|
|
14180
|
+
return this.recordObject({
|
|
14181
|
+
className: target.className,
|
|
14182
|
+
id: target.id,
|
|
14183
|
+
...target.label ? { label: target.label } : {},
|
|
14184
|
+
...target.fields ? { fields: target.fields } : {},
|
|
14185
|
+
...target.relationships ? { relationships: target.relationships } : {},
|
|
14186
|
+
states: {
|
|
14187
|
+
[machine.trim()]: {
|
|
14188
|
+
state: state.trim(),
|
|
14189
|
+
...target.source ? { source: target.source } : {},
|
|
14190
|
+
...target.cause ? { cause: target.cause } : {},
|
|
14191
|
+
...target.actorId ? { actorId: target.actorId } : {},
|
|
14192
|
+
...target.observedAt !== void 0 ? { observedAt: target.observedAt } : {},
|
|
14193
|
+
...target.force !== void 0 ? { force: target.force } : {},
|
|
14194
|
+
...target.metadata ? { metadata: target.metadata } : {}
|
|
14195
|
+
}
|
|
14196
|
+
}
|
|
14197
|
+
});
|
|
14198
|
+
}
|
|
14199
|
+
/**
|
|
14200
|
+
* Mirror product-owned workflow state into Granular without making Granular
|
|
14201
|
+
* own the customer application's state machine.
|
|
14202
|
+
*
|
|
14203
|
+
* Example:
|
|
14204
|
+
* `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
|
|
14205
|
+
*/
|
|
14206
|
+
state(target) {
|
|
14207
|
+
const observe = async (machineName, stateName, input = {}) => {
|
|
14208
|
+
const observedState = input.observedState || input.state || stateName;
|
|
14209
|
+
if (!observedState) {
|
|
14210
|
+
throw new Error("State observation requires a target state");
|
|
14211
|
+
}
|
|
14212
|
+
return this.recordState({
|
|
14213
|
+
...target,
|
|
14214
|
+
machine: machineName,
|
|
14215
|
+
state: observedState,
|
|
14216
|
+
...input.source ? { source: input.source } : {},
|
|
14217
|
+
...input.cause ? { cause: input.cause } : {},
|
|
14218
|
+
...input.actorId ? { actorId: input.actorId } : {},
|
|
14219
|
+
...input.observedAt !== void 0 ? { observedAt: input.observedAt } : {},
|
|
14220
|
+
...input.force !== void 0 ? { force: input.force } : {},
|
|
14221
|
+
...input.metadata ? { metadata: input.metadata } : {}
|
|
14222
|
+
});
|
|
14223
|
+
};
|
|
14224
|
+
return new Proxy(
|
|
14225
|
+
{},
|
|
14226
|
+
{
|
|
14227
|
+
get: (_target, machineProperty) => {
|
|
14228
|
+
if (typeof machineProperty !== "string") return void 0;
|
|
14229
|
+
return new Proxy(
|
|
14230
|
+
{},
|
|
14231
|
+
{
|
|
14232
|
+
get: (_machineTarget, stateProperty) => {
|
|
14233
|
+
if (stateProperty === "to") {
|
|
14234
|
+
return (stateName, input) => observe(machineProperty, stateName, input || {});
|
|
14235
|
+
}
|
|
14236
|
+
if (typeof stateProperty !== "string") return void 0;
|
|
14237
|
+
return (input) => observe(
|
|
14238
|
+
machineProperty,
|
|
14239
|
+
stateNameFromMethodName(stateProperty),
|
|
14240
|
+
input || {}
|
|
14241
|
+
);
|
|
14242
|
+
}
|
|
14243
|
+
}
|
|
14244
|
+
);
|
|
14245
|
+
}
|
|
14246
|
+
}
|
|
14247
|
+
);
|
|
14248
|
+
}
|
|
13513
14249
|
get feedback() {
|
|
13514
14250
|
return {
|
|
13515
14251
|
list: async () => this.listFeedback()
|
|
13516
14252
|
};
|
|
13517
14253
|
}
|
|
14254
|
+
get manualActions() {
|
|
14255
|
+
return {
|
|
14256
|
+
record: (input) => this.recordManualAction(input),
|
|
14257
|
+
list: (options = {}) => this.listManualActions(options),
|
|
14258
|
+
suggest: (options = {}) => this.suggestManualActions(options)
|
|
14259
|
+
};
|
|
14260
|
+
}
|
|
14261
|
+
get artifactApprovals() {
|
|
14262
|
+
return {
|
|
14263
|
+
list: (options = {}) => this.listArtifactApprovals(options),
|
|
14264
|
+
decide: (approvalTaskId, input) => this.decideArtifactApproval(approvalTaskId, input)
|
|
14265
|
+
};
|
|
14266
|
+
}
|
|
13518
14267
|
/**
|
|
13519
14268
|
* Sessionless environments do not own a live transport, so disconnecting the
|
|
13520
14269
|
* environment handle itself is a no-op. This keeps the public surface
|
|
@@ -13593,6 +14342,50 @@ var Environment = class _Environment {
|
|
|
13593
14342
|
const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
|
|
13594
14343
|
return Array.isArray(response.items) ? response.items : [];
|
|
13595
14344
|
}
|
|
14345
|
+
async recordManualAction(input) {
|
|
14346
|
+
const body = {
|
|
14347
|
+
...input,
|
|
14348
|
+
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
|
|
14349
|
+
};
|
|
14350
|
+
return this.controlPlaneRequest(
|
|
14351
|
+
`/control/environments/${this.environmentId}/manual-actions`,
|
|
14352
|
+
{
|
|
14353
|
+
method: "POST",
|
|
14354
|
+
body: JSON.stringify(body)
|
|
14355
|
+
}
|
|
14356
|
+
);
|
|
14357
|
+
}
|
|
14358
|
+
async listManualActions(options = {}) {
|
|
14359
|
+
const query = new URLSearchParams();
|
|
14360
|
+
appendQueryOptions(query, options);
|
|
14361
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14362
|
+
return this.controlPlaneRequest(`/control/environments/${this.environmentId}/manual-actions${suffix}`);
|
|
14363
|
+
}
|
|
14364
|
+
async suggestManualActions(options = {}) {
|
|
14365
|
+
const query = new URLSearchParams();
|
|
14366
|
+
appendQueryOptions(query, options);
|
|
14367
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14368
|
+
return this.controlPlaneRequest(
|
|
14369
|
+
`/control/environments/${this.environmentId}/manual-actions/suggestions${suffix}`
|
|
14370
|
+
);
|
|
14371
|
+
}
|
|
14372
|
+
async listArtifactApprovals(options = {}) {
|
|
14373
|
+
const query = new URLSearchParams();
|
|
14374
|
+
appendQueryOptions(query, options);
|
|
14375
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
14376
|
+
return this.controlPlaneRequest(
|
|
14377
|
+
`/control/environments/${this.environmentId}/artifact-approvals${suffix}`
|
|
14378
|
+
);
|
|
14379
|
+
}
|
|
14380
|
+
async decideArtifactApproval(approvalTaskId, input) {
|
|
14381
|
+
return this.controlPlaneRequest(
|
|
14382
|
+
`/control/environments/${this.environmentId}/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
14383
|
+
{
|
|
14384
|
+
method: "POST",
|
|
14385
|
+
body: JSON.stringify(input)
|
|
14386
|
+
}
|
|
14387
|
+
);
|
|
14388
|
+
}
|
|
13596
14389
|
getRuntimeBaseUrl() {
|
|
13597
14390
|
return deriveRuntimeBaseUrl(this._apiEndpoint);
|
|
13598
14391
|
}
|
|
@@ -14417,10 +15210,11 @@ var Environment = class _Environment {
|
|
|
14417
15210
|
if (!Array.isArray(records) || records.length === 0) {
|
|
14418
15211
|
return [];
|
|
14419
15212
|
}
|
|
15213
|
+
const recordsToWrite = records.map(preserveRecordObjectRealId);
|
|
14420
15214
|
const batchSize = Math.max(
|
|
14421
15215
|
1,
|
|
14422
15216
|
Math.min(
|
|
14423
|
-
|
|
15217
|
+
recordsToWrite.length,
|
|
14424
15218
|
options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
|
|
14425
15219
|
)
|
|
14426
15220
|
);
|
|
@@ -14428,8 +15222,8 @@ var Environment = class _Environment {
|
|
|
14428
15222
|
MAX_RECORD_OBJECTS_CONCURRENCY,
|
|
14429
15223
|
Math.max(1, options?.concurrency ?? 1)
|
|
14430
15224
|
);
|
|
14431
|
-
const plans = planRecordObjectsChunks(
|
|
14432
|
-
const total =
|
|
15225
|
+
const plans = planRecordObjectsChunks(recordsToWrite, batchSize);
|
|
15226
|
+
const total = recordsToWrite.length;
|
|
14433
15227
|
const results = new Array(total);
|
|
14434
15228
|
const onChunk = options?.onChunkComplete;
|
|
14435
15229
|
for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
|
|
@@ -14500,12 +15294,13 @@ var Environment = class _Environment {
|
|
|
14500
15294
|
* synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
|
|
14501
15295
|
*/
|
|
14502
15296
|
async enqueueRecordImport(records, options = {}) {
|
|
15297
|
+
const recordsToImport = records.map(preserveRecordObjectRealId);
|
|
14503
15298
|
return this.controlPlaneRequest(
|
|
14504
15299
|
`/control/environments/${this.environmentId}/record-imports`,
|
|
14505
15300
|
{
|
|
14506
15301
|
method: "POST",
|
|
14507
15302
|
body: JSON.stringify({
|
|
14508
|
-
records,
|
|
15303
|
+
records: recordsToImport,
|
|
14509
15304
|
batchSize: options.batchSize,
|
|
14510
15305
|
setupRunId: options.setupRunId,
|
|
14511
15306
|
writeMode: options.writeMode
|
|
@@ -14613,11 +15408,7 @@ var EnvironmentSession = class extends Session {
|
|
|
14613
15408
|
}
|
|
14614
15409
|
buildSessionDataUrl(path2, query) {
|
|
14615
15410
|
const searchParams = new URLSearchParams();
|
|
14616
|
-
|
|
14617
|
-
if (value !== null && typeof value !== "undefined" && value !== "") {
|
|
14618
|
-
searchParams.set(key, String(value));
|
|
14619
|
-
}
|
|
14620
|
-
}
|
|
15411
|
+
appendQueryOptions(searchParams, query);
|
|
14621
15412
|
const queryString = searchParams.toString();
|
|
14622
15413
|
return `${this.environment.runtimeBaseUrl}${this.sessionDataRoutePrefix}/${encodeURIComponent(this.sessionId)}${path2}${queryString ? `?${queryString}` : ""}`;
|
|
14623
15414
|
}
|
|
@@ -14700,9 +15491,108 @@ var EnvironmentSession = class extends Session {
|
|
|
14700
15491
|
),
|
|
14701
15492
|
get: (jobId) => this.sessionDataRequest(
|
|
14702
15493
|
`/jobs/${encodeURIComponent(jobId)}`
|
|
15494
|
+
),
|
|
15495
|
+
latest: async (options = {}) => {
|
|
15496
|
+
const page = await this.sessionDataRequest("/jobs", {
|
|
15497
|
+
status: options.status || "all",
|
|
15498
|
+
latest: true,
|
|
15499
|
+
limit: 1
|
|
15500
|
+
});
|
|
15501
|
+
return page.items[0] || null;
|
|
15502
|
+
}
|
|
15503
|
+
};
|
|
15504
|
+
}
|
|
15505
|
+
get artifacts() {
|
|
15506
|
+
return {
|
|
15507
|
+
list: (options = {}) => {
|
|
15508
|
+
const queryOptions = { ...options };
|
|
15509
|
+
if (options.target) {
|
|
15510
|
+
queryOptions.targetClassName = options.target.className;
|
|
15511
|
+
queryOptions.targetId = options.target.id;
|
|
15512
|
+
delete queryOptions.target;
|
|
15513
|
+
}
|
|
15514
|
+
return this.sessionDataRequest("/artifacts", queryOptions);
|
|
15515
|
+
},
|
|
15516
|
+
listForLatestJob: (options = {}) => this.artifacts.list({
|
|
15517
|
+
...options,
|
|
15518
|
+
latestJob: true
|
|
15519
|
+
}),
|
|
15520
|
+
get: (artifactId) => this.sessionDataRequest(
|
|
15521
|
+
`/artifacts/${encodeURIComponent(artifactId)}`
|
|
15522
|
+
),
|
|
15523
|
+
create: (artifact) => this.sessionDataRequest(
|
|
15524
|
+
"/artifacts",
|
|
15525
|
+
void 0,
|
|
15526
|
+
{
|
|
15527
|
+
method: "POST",
|
|
15528
|
+
body: artifact
|
|
15529
|
+
}
|
|
15530
|
+
),
|
|
15531
|
+
updateInputs: (artifactId, patch) => this.sessionDataRequest(
|
|
15532
|
+
`/artifacts/${encodeURIComponent(artifactId)}`,
|
|
15533
|
+
void 0,
|
|
15534
|
+
{
|
|
15535
|
+
method: "PATCH",
|
|
15536
|
+
body: patch
|
|
15537
|
+
}
|
|
15538
|
+
),
|
|
15539
|
+
validate: (artifactId) => this.sessionDataRequest(
|
|
15540
|
+
`/artifacts/${encodeURIComponent(artifactId)}/validate`,
|
|
15541
|
+
void 0,
|
|
15542
|
+
{ method: "POST" }
|
|
15543
|
+
),
|
|
15544
|
+
execute: (artifactId, options) => this.sessionDataRequest(
|
|
15545
|
+
`/artifacts/${encodeURIComponent(artifactId)}/execute`,
|
|
15546
|
+
void 0,
|
|
15547
|
+
{ method: "POST", body: options }
|
|
15548
|
+
),
|
|
15549
|
+
approve: (artifactId, options) => this.sessionDataRequest(
|
|
15550
|
+
`/artifacts/${encodeURIComponent(artifactId)}/approve`,
|
|
15551
|
+
void 0,
|
|
15552
|
+
{ method: "POST", body: options }
|
|
15553
|
+
),
|
|
15554
|
+
cancel: (artifactId) => this.sessionDataRequest(
|
|
15555
|
+
`/artifacts/${encodeURIComponent(artifactId)}/cancel`,
|
|
15556
|
+
void 0,
|
|
15557
|
+
{ method: "POST" }
|
|
14703
15558
|
)
|
|
14704
15559
|
};
|
|
14705
15560
|
}
|
|
15561
|
+
get manualActions() {
|
|
15562
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15563
|
+
return {
|
|
15564
|
+
record: (input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15565
|
+
"/manual-actions",
|
|
15566
|
+
void 0,
|
|
15567
|
+
{
|
|
15568
|
+
method: "POST",
|
|
15569
|
+
body: { ...input, sessionId: this.sessionId }
|
|
15570
|
+
}
|
|
15571
|
+
) : this.environment.manualActions.record({
|
|
15572
|
+
...input,
|
|
15573
|
+
sessionId: this.sessionId
|
|
15574
|
+
}),
|
|
15575
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/manual-actions", { ...options, sessionId: this.sessionId }) : this.environment.manualActions.list({
|
|
15576
|
+
...options,
|
|
15577
|
+
sessionId: this.sessionId
|
|
15578
|
+
}),
|
|
15579
|
+
suggest: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15580
|
+
"/manual-actions/suggestions",
|
|
15581
|
+
options
|
|
15582
|
+
) : this.environment.manualActions.suggest(options)
|
|
15583
|
+
};
|
|
15584
|
+
}
|
|
15585
|
+
get artifactApprovals() {
|
|
15586
|
+
const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
|
|
15587
|
+
return {
|
|
15588
|
+
list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/artifact-approvals", options) : this.environment.artifactApprovals.list(options),
|
|
15589
|
+
decide: (approvalTaskId, input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
|
|
15590
|
+
`/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
|
|
15591
|
+
void 0,
|
|
15592
|
+
{ method: "POST", body: input }
|
|
15593
|
+
) : this.environment.artifactApprovals.decide(approvalTaskId, input)
|
|
15594
|
+
};
|
|
15595
|
+
}
|
|
14706
15596
|
get files() {
|
|
14707
15597
|
return {
|
|
14708
15598
|
list: (options = {}) => this.sessionDataRequest(
|
|
@@ -14783,13 +15673,16 @@ var EnvironmentSession = class extends Session {
|
|
|
14783
15673
|
get transcript() {
|
|
14784
15674
|
return {
|
|
14785
15675
|
list: async (options = {}) => {
|
|
14786
|
-
const [messages, jobs, entries, lists] = await Promise.all([
|
|
15676
|
+
const [messages, jobs, entries, lists, artifacts] = await Promise.all([
|
|
14787
15677
|
this.collectAllSessionItems(this.messages.list),
|
|
14788
15678
|
this.collectAllSessionItems(
|
|
14789
15679
|
(pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
|
|
14790
15680
|
),
|
|
14791
15681
|
this.collectAllSessionItems(this.heap.entries.list),
|
|
14792
|
-
this.collectAllSessionItems(this.heap.lists.list)
|
|
15682
|
+
this.collectAllSessionItems(this.heap.lists.list),
|
|
15683
|
+
this.collectAllSessionItems(
|
|
15684
|
+
(pageOptions) => this.artifacts.list({ ...pageOptions, status: "all" })
|
|
15685
|
+
)
|
|
14793
15686
|
]);
|
|
14794
15687
|
const liveDoc = {
|
|
14795
15688
|
conversation: { messages },
|
|
@@ -14803,6 +15696,21 @@ var EnvironmentSession = class extends Session {
|
|
|
14803
15696
|
(entry) => Boolean(entry)
|
|
14804
15697
|
)
|
|
14805
15698
|
)
|
|
15699
|
+
},
|
|
15700
|
+
artifacts: {
|
|
15701
|
+
byId: Object.fromEntries(
|
|
15702
|
+
artifacts.map((artifact) => {
|
|
15703
|
+
return artifact?.artifactId ? [
|
|
15704
|
+
artifact.artifactId,
|
|
15705
|
+
artifact
|
|
15706
|
+
] : null;
|
|
15707
|
+
}).filter(
|
|
15708
|
+
(entry) => Boolean(entry)
|
|
15709
|
+
)
|
|
15710
|
+
),
|
|
15711
|
+
order: artifacts.map((artifact) => artifact?.artifactId).filter(
|
|
15712
|
+
(artifactId) => Boolean(artifactId)
|
|
15713
|
+
)
|
|
14806
15714
|
}
|
|
14807
15715
|
};
|
|
14808
15716
|
const heap = normalizeHeapSnapshot({
|
|
@@ -14879,6 +15787,12 @@ var EnvironmentSession = class extends Session {
|
|
|
14879
15787
|
async recordObject(options) {
|
|
14880
15788
|
return this.environment.recordObject(options);
|
|
14881
15789
|
}
|
|
15790
|
+
async recordState(input) {
|
|
15791
|
+
return this.environment.recordState(input);
|
|
15792
|
+
}
|
|
15793
|
+
state(target) {
|
|
15794
|
+
return this.environment.state(target);
|
|
15795
|
+
}
|
|
14882
15796
|
async recordObjects(records, options) {
|
|
14883
15797
|
return this.environment.recordObjects(records, options);
|
|
14884
15798
|
}
|
|
@@ -15706,15 +16620,43 @@ var Granular = class _Granular {
|
|
|
15706
16620
|
const effects = Array.from(
|
|
15707
16621
|
this.getSandboxEffectMap(host.sandboxId).values()
|
|
15708
16622
|
).map((effect) => this.serializeEffect(effect));
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
16623
|
+
let acceptedCount = 0;
|
|
16624
|
+
const rejected = [];
|
|
16625
|
+
try {
|
|
16626
|
+
await withTimeout(
|
|
16627
|
+
host.wsClient.call("effects.resetCatalog", {}),
|
|
16628
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16629
|
+
`effects.resetCatalog for sandbox ${host.sandboxId}`
|
|
16630
|
+
);
|
|
16631
|
+
for (const batch of chunkItems(effects, EFFECT_CATALOG_SYNC_BATCH_SIZE)) {
|
|
16632
|
+
const result = await withTimeout(
|
|
16633
|
+
host.wsClient.call("effects.addCatalog", {
|
|
16634
|
+
effects: batch
|
|
16635
|
+
}),
|
|
16636
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16637
|
+
`effects.addCatalog for sandbox ${host.sandboxId}`
|
|
16638
|
+
);
|
|
16639
|
+
acceptedCount += typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16640
|
+
if (Array.isArray(result?.rejected)) {
|
|
16641
|
+
rejected.push(...result.rejected);
|
|
16642
|
+
}
|
|
16643
|
+
}
|
|
16644
|
+
} catch (error) {
|
|
16645
|
+
if (!isUnsupportedEffectCatalogMutation(error)) {
|
|
16646
|
+
throw error;
|
|
16647
|
+
}
|
|
16648
|
+
const result = await withTimeout(
|
|
16649
|
+
host.wsClient.call("effects.publishCatalog", {
|
|
16650
|
+
effects
|
|
16651
|
+
}),
|
|
16652
|
+
EFFECT_CATALOG_SYNC_TIMEOUT_MS,
|
|
16653
|
+
`effects.publishCatalog for sandbox ${host.sandboxId}`
|
|
16654
|
+
);
|
|
16655
|
+
acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
16656
|
+
if (Array.isArray(result?.rejected)) {
|
|
16657
|
+
rejected.push(...result.rejected);
|
|
16658
|
+
}
|
|
16659
|
+
}
|
|
15718
16660
|
if (acceptedCount === 0 && rejected.length > 0) {
|
|
15719
16661
|
const detail = rejected.map(
|
|
15720
16662
|
(entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`
|
|
@@ -16940,6 +17882,7 @@ var HARNESS_V3_FRONTEND_ACTIONS_MODULE = "@granular/actions/frontend";
|
|
|
16940
17882
|
var HARNESS_V3_CSV_MODULE = "@granular/utils/csv";
|
|
16941
17883
|
var HARNESS_V3_XLSX_MODULE = "@granular/utils/xlsx";
|
|
16942
17884
|
var LEGACY_SANDBOX_TOOLS_MODULE_PATTERN = "\\.\\/sandbox-tools(?:\\.js)?";
|
|
17885
|
+
var HARNESS_V3_RUNTIME_MODULE_PATTERN = "@granular/(?:agent|session|domain(?:/[A-Za-z_$][\\w$]*)?|actions/(?:backend|frontend)|utils/(?:csv|xlsx))";
|
|
16943
17886
|
function hasNamedModuleImport(source, moduleName, name) {
|
|
16944
17887
|
const escapedModule = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16945
17888
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -16998,6 +17941,15 @@ function reviewGeneratedJobCode(code, _options = {}) {
|
|
|
16998
17941
|
message: "Generated code must use static top-level ESM imports from the Harness v3 runtime modules. Do not use dynamic import(...)."
|
|
16999
17942
|
});
|
|
17000
17943
|
}
|
|
17944
|
+
if (new RegExp(
|
|
17945
|
+
`import\\s+\\*\\s+as\\s+[A-Za-z_$][\\w$]*\\s+from\\s*['"]${HARNESS_V3_RUNTIME_MODULE_PATTERN}['"]`
|
|
17946
|
+
).test(normalized)) {
|
|
17947
|
+
issues.push({
|
|
17948
|
+
code: "runtime_namespace_import",
|
|
17949
|
+
severity: "error",
|
|
17950
|
+
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"`.'
|
|
17951
|
+
});
|
|
17952
|
+
}
|
|
17001
17953
|
if (/\bprocess\.exit\s*\(/.test(normalized)) {
|
|
17002
17954
|
issues.push({
|
|
17003
17955
|
code: "process_exit",
|
|
@@ -18017,6 +18969,31 @@ function buildGranularAgentHeapBlock(heapSummary) {
|
|
|
18017
18969
|
entries: {}
|
|
18018
18970
|
});
|
|
18019
18971
|
}
|
|
18972
|
+
function buildGranularAgentManualActionMemorySummary(input) {
|
|
18973
|
+
const maxItems = Math.max(1, Math.min(12, input.maxItems ?? 8));
|
|
18974
|
+
const suggestions = (input.suggestions || []).filter((suggestion) => suggestion?.actionKey).slice(0, maxItems).map((suggestion) => ({
|
|
18975
|
+
actionKey: suggestion.actionKey,
|
|
18976
|
+
label: suggestion.label || null,
|
|
18977
|
+
targetClassName: suggestion.targetClassName || null,
|
|
18978
|
+
count: typeof suggestion.count === "number" && Number.isFinite(suggestion.count) ? suggestion.count : null,
|
|
18979
|
+
subjectCount: typeof suggestion.subjectCount === "number" && Number.isFinite(suggestion.subjectCount) ? suggestion.subjectCount : null,
|
|
18980
|
+
successCount: typeof suggestion.successCount === "number" && Number.isFinite(suggestion.successCount) ? suggestion.successCount : null,
|
|
18981
|
+
failureCount: typeof suggestion.failureCount === "number" && Number.isFinite(suggestion.failureCount) ? suggestion.failureCount : null,
|
|
18982
|
+
lastOccurredAt: typeof suggestion.lastOccurredAt === "number" && Number.isFinite(suggestion.lastOccurredAt) ? suggestion.lastOccurredAt : null,
|
|
18983
|
+
sampleTargetIds: Array.isArray(suggestion.sampleTargetIds) ? suggestion.sampleTargetIds.filter(
|
|
18984
|
+
(id) => typeof id === "string" && id.trim().length > 0
|
|
18985
|
+
).slice(0, 6) : []
|
|
18986
|
+
}));
|
|
18987
|
+
return [
|
|
18988
|
+
renderConstBlock("manualActionMemory", {
|
|
18989
|
+
suggestions
|
|
18990
|
+
}),
|
|
18991
|
+
"Use manualActionMemory only as behavioral context for likely next actions. Ground the current target and validate permissions before creating or running prepared actions."
|
|
18992
|
+
].join("\n");
|
|
18993
|
+
}
|
|
18994
|
+
function buildGranularAgentManualActionBlock(manualActionSummary) {
|
|
18995
|
+
return manualActionSummary?.trim() || buildGranularAgentManualActionMemorySummary({ suggestions: [] });
|
|
18996
|
+
}
|
|
18020
18997
|
function projectSessionFileSummary(liveDoc) {
|
|
18021
18998
|
const files = asRecord4(liveDoc?.files);
|
|
18022
18999
|
const byId = asRecord4(files?.byId) || {};
|
|
@@ -18048,8 +19025,12 @@ function buildGranularAgentFileBlock(fileSummary) {
|
|
|
18048
19025
|
function extractRuntimeContractExports(domainBlock) {
|
|
18049
19026
|
const classes = /* @__PURE__ */ new Set();
|
|
18050
19027
|
const actions = /* @__PURE__ */ new Set();
|
|
18051
|
-
const
|
|
18052
|
-
for (const match of domainBlock.matchAll(
|
|
19028
|
+
const classConstPattern = /export\s+declare\s+const\s+([A-Za-z_$][\w$]*)\s*:\s*EntityClass\b/g;
|
|
19029
|
+
for (const match of domainBlock.matchAll(classConstPattern)) {
|
|
19030
|
+
classes.add(match[1]);
|
|
19031
|
+
}
|
|
19032
|
+
const classDeclPattern = /export\s+declare\s+class\s+([A-Za-z_$][\w$]*)\b/g;
|
|
19033
|
+
for (const match of domainBlock.matchAll(classDeclPattern)) {
|
|
18053
19034
|
classes.add(match[1]);
|
|
18054
19035
|
}
|
|
18055
19036
|
const actionPattern = /export\s+declare\s+function\s+([A-Za-z_$][\w$]*)/g;
|
|
@@ -18554,6 +19535,9 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18554
19535
|
});
|
|
18555
19536
|
const referentBlock = buildGranularAgentReferentBlock(input.referentSummary);
|
|
18556
19537
|
const loopBlock = buildGranularAgentLoopBlock(input.loopSummary);
|
|
19538
|
+
const manualActionBlock = buildGranularAgentManualActionBlock(
|
|
19539
|
+
input.manualActionSummary
|
|
19540
|
+
);
|
|
18557
19541
|
const knownFactsBlock = renderConstBlock(
|
|
18558
19542
|
"knownFacts",
|
|
18559
19543
|
buildKnownFactsFromCheckpoint(input.checkpoint)
|
|
@@ -18567,16 +19551,15 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18567
19551
|
- \`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.
|
|
18568
19552
|
- 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.
|
|
18569
19553
|
- 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.
|
|
18570
|
-
- When \`replyToUser(...)\` mentions a grounded record that should remain clickable/referable, wrap only the visible record label in a self-closing inline reference tag
|
|
18571
|
-
- Treat \`showObjects(...)\` as the UI display call for user-visible records,
|
|
18572
|
-
-
|
|
18573
|
-
-
|
|
18574
|
-
-
|
|
18575
|
-
-
|
|
19554
|
+
- 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.
|
|
19555
|
+
- 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"] })\`.
|
|
19556
|
+
- \`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(...)\`.
|
|
19557
|
+
- 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.
|
|
19558
|
+
- 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()\`.
|
|
19559
|
+
- 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.
|
|
18576
19560
|
- 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.
|
|
18577
19561
|
- 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.
|
|
18578
|
-
-
|
|
18579
|
-
- 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.
|
|
19562
|
+
- 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.
|
|
18580
19563
|
- 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\`.
|
|
18581
19564
|
- \`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.
|
|
18582
19565
|
- 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.
|
|
@@ -18587,7 +19570,7 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
18587
19570
|
- When using code, assistant text must be empty or one brief summary.
|
|
18588
19571
|
- Code must be plain runnable JavaScript with top-level await.
|
|
18589
19572
|
- Use [Runtime Imports] as the authoritative module map. Import only listed module exports.
|
|
18590
|
-
- 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.
|
|
19573
|
+
- 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.
|
|
18591
19574
|
- 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.
|
|
18592
19575
|
- 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.
|
|
18593
19576
|
- 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\`.
|
|
@@ -18650,6 +19633,7 @@ ${workflowRules}
|
|
|
18650
19633
|
High-priority execution rules:
|
|
18651
19634
|
- 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.
|
|
18652
19635
|
- 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.
|
|
19636
|
+
- 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.
|
|
18653
19637
|
- 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.
|
|
18654
19638
|
- 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.
|
|
18655
19639
|
- 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.
|
|
@@ -18693,7 +19677,7 @@ Intent resolution:
|
|
|
18693
19677
|
- 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.
|
|
18694
19678
|
- 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.
|
|
18695
19679
|
- 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.
|
|
18696
|
-
- 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
|
|
19680
|
+
- 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.
|
|
18697
19681
|
- 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.
|
|
18698
19682
|
- Never call \`.get({ path: "" })\`; an empty path is not a saved reference.
|
|
18699
19683
|
- 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.
|
|
@@ -18820,20 +19804,10 @@ Ask the user when:
|
|
|
18820
19804
|
- the target is unique but the requested action is unclear
|
|
18821
19805
|
|
|
18822
19806
|
Relationship filters:
|
|
18823
|
-
-
|
|
18824
|
-
-
|
|
18825
|
-
-
|
|
18826
|
-
-
|
|
18827
|
-
- 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.
|
|
18828
|
-
- 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.
|
|
18829
|
-
- Use \`some\` only when the generated TypeScript type says \`ManyRelationFilter\`.
|
|
18830
|
-
- 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.
|
|
18831
|
-
- Use \`{ relationship: { id: "record_id" } }\` or \`{ relationship: { path: "class_record_id" } }\` when matching a known related record.
|
|
18832
|
-
- 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\`.
|
|
18833
|
-
- 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.
|
|
18834
|
-
- Use \`{ relationship: { is: { field: { equal_to: value } } } }\` only for nested field filters. Never put \`id\` or \`path\` inside \`is\`.
|
|
18835
|
-
- 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.
|
|
18836
|
-
- Do not pass a full record instance into a filter; if you already fetched a record, filter by its id or path instead.
|
|
19807
|
+
- Use the generated filter type as the authority: \`OneRelationFilter\` supports \`id\`, \`path\`, \`is\`, \`null\`, \`not_null\`; \`ManyRelationFilter\` supports those plus \`some\`.
|
|
19808
|
+
- Use \`id\` or \`path\` for a known related record; use \`is\` or \`some\` only for nested target-field filters.
|
|
19809
|
+
- 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.
|
|
19810
|
+
- Never pass a full record instance into a filter. Use its id/path or a declared relationship getter.
|
|
18837
19811
|
${domainSections.docs ? `
|
|
18838
19812
|
Domain notes:
|
|
18839
19813
|
${domainSections.docs}
|
|
@@ -18844,6 +19818,23 @@ ${actionIndex}
|
|
|
18844
19818
|
- 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.
|
|
18845
19819
|
- 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(...)\`.
|
|
18846
19820
|
- Actions listed under "Class-level" are class/static methods. Call them on the imported class, e.g. \`await Item.action_name(...)\`.
|
|
19821
|
+
- 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.
|
|
19822
|
+
- For pure field-collection requests, target the class-level entry state handle; for submit/review requests, target the nearest requested later state.
|
|
19823
|
+
- Choose the nearest target state that matches the user's words. Do not aim at a later state just because it is reachable.
|
|
19824
|
+
- 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\`.
|
|
19825
|
+
- 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.
|
|
19826
|
+
- 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.
|
|
19827
|
+
- 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()\`.
|
|
19828
|
+
- 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.
|
|
19829
|
+
- 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.
|
|
19830
|
+
- 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.
|
|
19831
|
+
- 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.
|
|
19832
|
+
- 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.
|
|
19833
|
+
- 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.
|
|
19834
|
+
- 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.
|
|
19835
|
+
- 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.
|
|
19836
|
+
- 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.
|
|
19837
|
+
- Use \`await prepared.show()\` or \`await actions.show(prepared)\` only to display an already-created prepared action again.
|
|
18847
19838
|
- 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.
|
|
18848
19839
|
- Never call a record-level action as \`Class.action_name(...)\`; that method will not exist.
|
|
18849
19840
|
- 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.
|
|
@@ -18874,6 +19865,8 @@ ${loopBlock}
|
|
|
18874
19865
|
|
|
18875
19866
|
${knownFactsBlock}
|
|
18876
19867
|
|
|
19868
|
+
${manualActionBlock}
|
|
19869
|
+
|
|
18877
19870
|
[Request]
|
|
18878
19871
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
18879
19872
|
}
|
|
@@ -19624,6 +20617,8 @@ function modelOutputInstruction() {
|
|
|
19624
20617
|
'Do not use "action":"reply" to say a record is not grounded yet; if the request names or describes a domain record, use "action":"job" and ground it from session state, relationships, searches, or visible read-only actions first.',
|
|
19625
20618
|
'Before claiming you lack access, inspect the visible action list. If a visible read-only search, lookup, list, guidance, note, policy, or knowledge action can satisfy a "check", "find", "look up", or "whether we have guidance" request, choose "action":"job" and call it.',
|
|
19626
20619
|
"Generated code must not report no matches for the primary human-described anchor after a single zero-result list/find/page call. Before that primary no-match return, retry the primary anchor with fewer text constraints or a distinct fallback such as owner/container grounding, relationship traversal, exact-id/path lookup, or shorter target-local search.",
|
|
20620
|
+
"If the latest request names an importable entity type, generated code must ground that class first; a previously installed parent class or related action method is not a substitute. After zero results in one class, pivot to the latest named importable class before reporting no match.",
|
|
20621
|
+
"When the user says they have a document/work item/event but no matching record exists yet, generated code must check the visible class-level new-record/create/preparation surface before returning no-match; if required create inputs are still missing and no prepared action can collect them, ask only for those inputs.",
|
|
19627
20622
|
'Use "action":"job" when the next step should run code or mutate workflow state.',
|
|
19628
20623
|
'When action is "job", include runnable code in "code" and emit the "code" field before any non-empty "reply" field so generated code comments can stream as progress.',
|
|
19629
20624
|
"Generated job code must use plain ASCII punctuation in string literals and comments. Do not use curly quotes, smart apostrophes, en dashes, em dashes, or other typographic punctuation in code.",
|
|
@@ -19693,7 +20688,12 @@ function createOpenAIChatTurnGenerator(options) {
|
|
|
19693
20688
|
|
|
19694
20689
|
${modelOutputInstruction()}`
|
|
19695
20690
|
},
|
|
19696
|
-
...input.history
|
|
20691
|
+
...input.history.map(
|
|
20692
|
+
(message) => ({
|
|
20693
|
+
role: message.role,
|
|
20694
|
+
content: message.content
|
|
20695
|
+
})
|
|
20696
|
+
),
|
|
19697
20697
|
{ role: "user", content: input.request }
|
|
19698
20698
|
];
|
|
19699
20699
|
const payload = {
|
|
@@ -19712,11 +20712,12 @@ ${modelOutputInstruction()}`
|
|
|
19712
20712
|
let usage = null;
|
|
19713
20713
|
let requestId = null;
|
|
19714
20714
|
if (input.onTextDelta || input.onReplyDelta || input.onCodeDelta) {
|
|
19715
|
-
const
|
|
20715
|
+
const streamPayload = {
|
|
19716
20716
|
...payload,
|
|
19717
20717
|
stream: true,
|
|
19718
20718
|
stream_options: { include_usage: true }
|
|
19719
|
-
}
|
|
20719
|
+
};
|
|
20720
|
+
const stream = await client.chat.completions.create(streamPayload);
|
|
19720
20721
|
let streamedReply = "";
|
|
19721
20722
|
let streamedCode = "";
|
|
19722
20723
|
const emitReplyDelta = async () => {
|
|
@@ -19742,7 +20743,8 @@ ${modelOutputInstruction()}`
|
|
|
19742
20743
|
await input.onCodeDelta(delta);
|
|
19743
20744
|
};
|
|
19744
20745
|
for await (const event of stream) {
|
|
19745
|
-
|
|
20746
|
+
const eventRecord = event;
|
|
20747
|
+
requestId = requestId || event.id || (typeof eventRecord._request_id === "string" ? eventRecord._request_id : null);
|
|
19746
20748
|
usage = event.usage || usage;
|
|
19747
20749
|
const delta = event.choices?.[0]?.delta?.content;
|
|
19748
20750
|
const deltaText = typeof delta === "string" ? delta : Array.isArray(delta) ? delta.map((part) => asRecord6(part)?.text || "").join("") : "";
|
|
@@ -19756,14 +20758,13 @@ ${modelOutputInstruction()}`
|
|
|
19756
20758
|
await emitCodeDelta();
|
|
19757
20759
|
raw = { streamed: true, model, usage, request_id: requestId };
|
|
19758
20760
|
} else {
|
|
19759
|
-
const completion = await client.chat.completions.create(
|
|
19760
|
-
|
|
19761
|
-
);
|
|
20761
|
+
const completion = await client.chat.completions.create(payload);
|
|
20762
|
+
const completionRecord = completion;
|
|
19762
20763
|
raw = completion;
|
|
19763
20764
|
usage = completion.usage;
|
|
19764
|
-
requestId = (typeof completion.id === "string" ? completion.id : null) || (typeof
|
|
20765
|
+
requestId = (typeof completion.id === "string" ? completion.id : null) || (typeof completionRecord._request_id === "string" ? completionRecord._request_id : null);
|
|
19765
20766
|
const content = asRecord6(
|
|
19766
|
-
asRecord6(completion.choices
|
|
20767
|
+
asRecord6(completion.choices[0])?.message
|
|
19767
20768
|
)?.content;
|
|
19768
20769
|
text = typeof content === "string" ? content : Array.isArray(content) ? content.map((part) => asRecord6(part)?.text || "").join("") : "";
|
|
19769
20770
|
}
|
|
@@ -20100,6 +21101,9 @@ async function generateTurnWithRepair(generator, input) {
|
|
|
20100
21101
|
"",
|
|
20101
21102
|
"The previous generated job code failed preflight review against [Runtime Imports] and the runtime contract.",
|
|
20102
21103
|
"Return a corrected JSON object. Keep the user's requested behavior, but fix every issue below before execution.",
|
|
21104
|
+
"If an issue says workflow path, blockers, permissions, or readiness were derived from raw status fields, remove the status/current-state ladder. Pick the declared state handle that matches the user's requested outcome, call plan()/blockers()/permissions() first, then open/show that handle or explain its structured blockers.",
|
|
21105
|
+
"If an issue says an unsafe type assertion was used, remove the cast and use declared fields or typed helpers directly. For state plans, use plan.blockers, plan.permissions, plan.steps, plan.summary, or blocker-formatting helpers without hand-written object casts.",
|
|
21106
|
+
"If the previous code stopped after no matching record for a user-supplied document/work item, preserve the lookup but check declared new-record/create/preparation surfaces next. Import the backend action module if needed, or ask only for missing required create inputs when no prepared action can collect them.",
|
|
20103
21107
|
"",
|
|
20104
21108
|
"Preflight issues:",
|
|
20105
21109
|
...issues.map((issue) => `- ${issue.code}: ${issue.message}`),
|