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