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