@granular-software/sdk 0.4.21 → 0.4.23
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/README.md +241 -151
- package/dist/agent-evals.d.mts +1 -1
- package/dist/agent-evals.d.ts +1 -1
- package/dist/agent-evals.js +240 -65
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +240 -65
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.js +126 -41
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +126 -41
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +566 -191
- package/dist/{client-DLGC0mJk.d.mts → client-CQFKsCTd.d.mts} +1 -1
- package/dist/{client-DLGC0mJk.d.ts → client-CQFKsCTd.d.ts} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +240 -65
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +240 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4707,7 +4707,9 @@ var Session = class {
|
|
|
4707
4707
|
}
|
|
4708
4708
|
}
|
|
4709
4709
|
if (!revision) {
|
|
4710
|
-
throw new Error(
|
|
4710
|
+
throw new Error(
|
|
4711
|
+
"No domain revision available. Register live effects or ensure the build schema is activated."
|
|
4712
|
+
);
|
|
4711
4713
|
}
|
|
4712
4714
|
const result = await this.client.call("job.submit", {
|
|
4713
4715
|
domainRevision: revision,
|
|
@@ -4743,7 +4745,11 @@ var Session = class {
|
|
|
4743
4745
|
const prompt = this.promptCache.get(promptId);
|
|
4744
4746
|
const resolvedAnswer = resolvePromptAnswer(prompt, answer);
|
|
4745
4747
|
this.promptCache.delete(promptId);
|
|
4746
|
-
await this.client.call("prompt.answer", {
|
|
4748
|
+
await this.client.call("prompt.answer", {
|
|
4749
|
+
promptId,
|
|
4750
|
+
answer: resolvedAnswer,
|
|
4751
|
+
value: resolvedAnswer
|
|
4752
|
+
});
|
|
4747
4753
|
}
|
|
4748
4754
|
/**
|
|
4749
4755
|
* Get the current list of available effects.
|
|
@@ -4775,7 +4781,8 @@ var Session = class {
|
|
|
4775
4781
|
for (const tool of cat.tools) {
|
|
4776
4782
|
if (!tool?.name) continue;
|
|
4777
4783
|
const existing = toolMap.get(tool.name);
|
|
4778
|
-
if (existing?.publishedAt && cat.publishedAt && existing.publishedAt > cat.publishedAt)
|
|
4784
|
+
if (existing?.publishedAt && cat.publishedAt && existing.publishedAt > cat.publishedAt)
|
|
4785
|
+
continue;
|
|
4779
4786
|
const isLocal = clientId === this.clientId;
|
|
4780
4787
|
const ready = isLocal ? this.effects.has(tool.name) || this.toolHandlers.has(tool.name) || this.instanceTools.has(tool.name) : true;
|
|
4781
4788
|
toolMap.set(tool.name, {
|
|
@@ -4813,7 +4820,10 @@ var Session = class {
|
|
|
4813
4820
|
return () => {
|
|
4814
4821
|
const listeners = this.eventListeners.get("effects:changed");
|
|
4815
4822
|
if (listeners) {
|
|
4816
|
-
this.eventListeners.set(
|
|
4823
|
+
this.eventListeners.set(
|
|
4824
|
+
"effects:changed",
|
|
4825
|
+
listeners.filter((h) => h !== handler)
|
|
4826
|
+
);
|
|
4817
4827
|
}
|
|
4818
4828
|
};
|
|
4819
4829
|
}
|
|
@@ -4829,7 +4839,10 @@ var Session = class {
|
|
|
4829
4839
|
return () => {
|
|
4830
4840
|
const listeners = this.eventListeners.get("tools:changed");
|
|
4831
4841
|
if (listeners) {
|
|
4832
|
-
this.eventListeners.set(
|
|
4842
|
+
this.eventListeners.set(
|
|
4843
|
+
"tools:changed",
|
|
4844
|
+
listeners.filter((h) => h !== handler)
|
|
4845
|
+
);
|
|
4833
4846
|
}
|
|
4834
4847
|
};
|
|
4835
4848
|
}
|
|
@@ -4837,11 +4850,16 @@ var Session = class {
|
|
|
4837
4850
|
* Get the current domain state and available tools
|
|
4838
4851
|
*/
|
|
4839
4852
|
async getDomain() {
|
|
4840
|
-
const summary = await this.client.call(
|
|
4853
|
+
const summary = await this.client.call(
|
|
4854
|
+
"domain.getSummary",
|
|
4855
|
+
{}
|
|
4856
|
+
);
|
|
4841
4857
|
if (summary.activeDomainRevision) {
|
|
4842
4858
|
this.currentDomainRevision = summary.activeDomainRevision;
|
|
4843
4859
|
} else {
|
|
4844
|
-
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
4860
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
4861
|
+
this.client.doc
|
|
4862
|
+
);
|
|
4845
4863
|
}
|
|
4846
4864
|
return summary;
|
|
4847
4865
|
}
|
|
@@ -5016,20 +5034,31 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5016
5034
|
off(event, handler) {
|
|
5017
5035
|
const handlers = this.eventListeners.get(event);
|
|
5018
5036
|
if (handlers) {
|
|
5019
|
-
this.eventListeners.set(
|
|
5037
|
+
this.eventListeners.set(
|
|
5038
|
+
event,
|
|
5039
|
+
handlers.filter((h) => h !== handler)
|
|
5040
|
+
);
|
|
5020
5041
|
}
|
|
5021
5042
|
}
|
|
5022
5043
|
// --- Internal ---
|
|
5023
5044
|
setupToolInvokeHandler() {
|
|
5024
5045
|
this.client.registerRpcHandler("tool.invoke", async (params) => {
|
|
5025
5046
|
const { callId, toolName, input } = params;
|
|
5026
|
-
this.emit("effect:invoke", {
|
|
5047
|
+
this.emit("effect:invoke", {
|
|
5048
|
+
callId,
|
|
5049
|
+
effectKey: toolName,
|
|
5050
|
+
toolName,
|
|
5051
|
+
input
|
|
5052
|
+
});
|
|
5027
5053
|
this.emit("tool:invoke", { callId, toolName, input });
|
|
5028
5054
|
const handler = this.toolHandlers.get(toolName);
|
|
5029
5055
|
if (!handler) {
|
|
5030
5056
|
await this.client.call("tool.result", {
|
|
5031
5057
|
callId,
|
|
5032
|
-
error: {
|
|
5058
|
+
error: {
|
|
5059
|
+
code: "TOOL_NOT_FOUND",
|
|
5060
|
+
message: `Tool handler not found: ${toolName}`
|
|
5061
|
+
}
|
|
5033
5062
|
});
|
|
5034
5063
|
return;
|
|
5035
5064
|
}
|
|
@@ -5038,7 +5067,11 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5038
5067
|
const invocationContext = this.buildLegacyEffectContext();
|
|
5039
5068
|
if (this.instanceTools.has(toolName) && input && typeof input === "object" && "_objectId" in input) {
|
|
5040
5069
|
const { _objectId, ...restParams } = input;
|
|
5041
|
-
result = await handler(
|
|
5070
|
+
result = await handler(
|
|
5071
|
+
_objectId,
|
|
5072
|
+
restParams,
|
|
5073
|
+
invocationContext
|
|
5074
|
+
);
|
|
5042
5075
|
} else {
|
|
5043
5076
|
result = await handler(input, invocationContext);
|
|
5044
5077
|
}
|
|
@@ -5050,7 +5083,11 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5050
5083
|
});
|
|
5051
5084
|
} catch (error) {
|
|
5052
5085
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5053
|
-
this.emit("effect:result", {
|
|
5086
|
+
this.emit("effect:result", {
|
|
5087
|
+
callId,
|
|
5088
|
+
effectKey: toolName,
|
|
5089
|
+
error: errorMessage
|
|
5090
|
+
});
|
|
5054
5091
|
this.emit("tool:result", { callId, error: errorMessage });
|
|
5055
5092
|
await this.client.call("tool.result", {
|
|
5056
5093
|
callId,
|
|
@@ -5060,7 +5097,10 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5060
5097
|
});
|
|
5061
5098
|
}
|
|
5062
5099
|
setupEventHandlers() {
|
|
5063
|
-
this.client.on(
|
|
5100
|
+
this.client.on(
|
|
5101
|
+
"open",
|
|
5102
|
+
(payload) => this.emit("open", payload || {})
|
|
5103
|
+
);
|
|
5064
5104
|
this.client.on("sync", (doc) => {
|
|
5065
5105
|
this.currentDomainRevision = this.extractDomainRevisionFromDoc(doc);
|
|
5066
5106
|
this.emit("sync", doc);
|
|
@@ -5074,8 +5114,14 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5074
5114
|
};
|
|
5075
5115
|
this.client.on("prompt", emitPrompt);
|
|
5076
5116
|
this.client.on("prompt.request", emitPrompt);
|
|
5077
|
-
this.client.on(
|
|
5078
|
-
|
|
5117
|
+
this.client.on(
|
|
5118
|
+
"disconnect",
|
|
5119
|
+
(payload) => this.emit("disconnect", payload || {})
|
|
5120
|
+
);
|
|
5121
|
+
this.client.on(
|
|
5122
|
+
"reconnect_error",
|
|
5123
|
+
(payload) => this.emit("reconnect_error", payload || {})
|
|
5124
|
+
);
|
|
5079
5125
|
this.client.on("job.status", (data) => {
|
|
5080
5126
|
this.emit("job:status", data);
|
|
5081
5127
|
});
|
|
@@ -5191,7 +5237,10 @@ function sanitizeFeedbackValue(value, depth = 0, seen = /* @__PURE__ */ new Weak
|
|
|
5191
5237
|
return "[Circular]";
|
|
5192
5238
|
}
|
|
5193
5239
|
seen.add(value);
|
|
5194
|
-
const entries = Object.entries(value).slice(
|
|
5240
|
+
const entries = Object.entries(value).slice(
|
|
5241
|
+
0,
|
|
5242
|
+
MAX_FEEDBACK_OBJECT_KEYS
|
|
5243
|
+
);
|
|
5195
5244
|
const sanitized = {};
|
|
5196
5245
|
for (const [key, entryValue] of entries) {
|
|
5197
5246
|
sanitized[key] = sanitizeFeedbackValue(entryValue, depth + 1, seen);
|
|
@@ -5242,12 +5291,18 @@ var JobImplementation = class {
|
|
|
5242
5291
|
if (progressData.execId === id || progressData.jobId === id) {
|
|
5243
5292
|
if (progressData.stdout) {
|
|
5244
5293
|
this.markStarted();
|
|
5245
|
-
this.metadata.stdout = [
|
|
5294
|
+
this.metadata.stdout = [
|
|
5295
|
+
...this.metadata.stdout,
|
|
5296
|
+
truncateFeedbackString(progressData.stdout)
|
|
5297
|
+
].slice(-100);
|
|
5246
5298
|
this.emit("stdout", progressData.stdout);
|
|
5247
5299
|
}
|
|
5248
5300
|
if (progressData.stderr) {
|
|
5249
5301
|
this.markStarted();
|
|
5250
|
-
this.metadata.stderr = [
|
|
5302
|
+
this.metadata.stderr = [
|
|
5303
|
+
...this.metadata.stderr,
|
|
5304
|
+
truncateFeedbackString(progressData.stderr)
|
|
5305
|
+
].slice(-100);
|
|
5251
5306
|
this.emit("stderr", progressData.stderr);
|
|
5252
5307
|
}
|
|
5253
5308
|
}
|
|
@@ -5269,12 +5324,18 @@ var JobImplementation = class {
|
|
|
5269
5324
|
});
|
|
5270
5325
|
this.client.on(`job.${id}.stdout`, (line) => {
|
|
5271
5326
|
this.markStarted();
|
|
5272
|
-
this.metadata.stdout = [
|
|
5327
|
+
this.metadata.stdout = [
|
|
5328
|
+
...this.metadata.stdout,
|
|
5329
|
+
truncateFeedbackString(String(line))
|
|
5330
|
+
].slice(-100);
|
|
5273
5331
|
this.emit("stdout", line);
|
|
5274
5332
|
});
|
|
5275
5333
|
this.client.on(`job.${id}.stderr`, (line) => {
|
|
5276
5334
|
this.markStarted();
|
|
5277
|
-
this.metadata.stderr = [
|
|
5335
|
+
this.metadata.stderr = [
|
|
5336
|
+
...this.metadata.stderr,
|
|
5337
|
+
truncateFeedbackString(String(line))
|
|
5338
|
+
].slice(-100);
|
|
5278
5339
|
this.emit("stderr", line);
|
|
5279
5340
|
});
|
|
5280
5341
|
this.client.on(`job.${id}.result`, (result) => {
|
|
@@ -5306,7 +5367,11 @@ var JobImplementation = class {
|
|
|
5306
5367
|
this.client.on("job.failed", (data) => {
|
|
5307
5368
|
const jobData = data;
|
|
5308
5369
|
if (jobData.jobId === id) {
|
|
5309
|
-
this.finalize(
|
|
5370
|
+
this.finalize(
|
|
5371
|
+
"failed",
|
|
5372
|
+
void 0,
|
|
5373
|
+
jobData.error || new Error("Job failed")
|
|
5374
|
+
);
|
|
5310
5375
|
this.emit("status", this.status);
|
|
5311
5376
|
}
|
|
5312
5377
|
});
|
|
@@ -5319,7 +5384,12 @@ var JobImplementation = class {
|
|
|
5319
5384
|
input: sanitizeFeedbackValue(d.input),
|
|
5320
5385
|
startedAt: d.timestamp || Date.now()
|
|
5321
5386
|
});
|
|
5322
|
-
this.emit("toolCallStart", {
|
|
5387
|
+
this.emit("toolCallStart", {
|
|
5388
|
+
callId: d.callId,
|
|
5389
|
+
toolName: d.toolName,
|
|
5390
|
+
input: d.input,
|
|
5391
|
+
timestamp: d.timestamp
|
|
5392
|
+
});
|
|
5323
5393
|
}
|
|
5324
5394
|
});
|
|
5325
5395
|
this.client.on("tool.call.end", (data) => {
|
|
@@ -5334,7 +5404,25 @@ var JobImplementation = class {
|
|
|
5334
5404
|
completedAt,
|
|
5335
5405
|
durationMs: typeof d.durationMs === "number" ? d.durationMs : void 0
|
|
5336
5406
|
});
|
|
5337
|
-
this.emit("toolCallEnd", {
|
|
5407
|
+
this.emit("toolCallEnd", {
|
|
5408
|
+
callId: d.callId,
|
|
5409
|
+
toolName: d.toolName,
|
|
5410
|
+
result: d.result,
|
|
5411
|
+
error: d.error,
|
|
5412
|
+
durationMs: d.durationMs,
|
|
5413
|
+
timestamp: d.timestamp
|
|
5414
|
+
});
|
|
5415
|
+
}
|
|
5416
|
+
});
|
|
5417
|
+
this.client.on("job.agent_message", (data) => {
|
|
5418
|
+
const d = data;
|
|
5419
|
+
if (d.jobId === id) {
|
|
5420
|
+
this.emit("agentMessage", {
|
|
5421
|
+
messageId: d.messageId,
|
|
5422
|
+
reply: typeof d.reply === "string" ? d.reply : "",
|
|
5423
|
+
show: d.show,
|
|
5424
|
+
timestamp: d.timestamp || Date.now()
|
|
5425
|
+
});
|
|
5338
5426
|
}
|
|
5339
5427
|
});
|
|
5340
5428
|
}
|
|
@@ -5404,7 +5492,9 @@ var JobImplementation = class {
|
|
|
5404
5492
|
}
|
|
5405
5493
|
upsertToolCall(next) {
|
|
5406
5494
|
const callId = next.callId || `tool-call-${Date.now()}`;
|
|
5407
|
-
const existingIndex = this.metadata.toolCalls.findIndex(
|
|
5495
|
+
const existingIndex = this.metadata.toolCalls.findIndex(
|
|
5496
|
+
(entry) => entry.callId === callId
|
|
5497
|
+
);
|
|
5408
5498
|
const existing = existingIndex >= 0 ? this.metadata.toolCalls[existingIndex] : void 0;
|
|
5409
5499
|
const merged = {
|
|
5410
5500
|
...existing,
|
|
@@ -13369,7 +13459,8 @@ function uniqueStrings(values, maxCount) {
|
|
|
13369
13459
|
}
|
|
13370
13460
|
function formatScalar(value) {
|
|
13371
13461
|
if (typeof value === "string") return JSON.stringify(value);
|
|
13372
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
13462
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
13463
|
+
return String(value);
|
|
13373
13464
|
if (value === null) return "null";
|
|
13374
13465
|
return "unknown";
|
|
13375
13466
|
}
|
|
@@ -13377,7 +13468,9 @@ function describeHeapEntry(entry, previewFieldLimit = 3) {
|
|
|
13377
13468
|
const headline = entry.label || entry.id || entry.path || "Unknown";
|
|
13378
13469
|
const pathLabel = entry.path && entry.path !== headline ? ` <${entry.path}>` : "";
|
|
13379
13470
|
const classLabel = entry.className || "unknown";
|
|
13380
|
-
const preview = asArray(entry.fields).filter(
|
|
13471
|
+
const preview = asArray(entry.fields).filter(
|
|
13472
|
+
(field) => field?.name && field.name !== "_realId" && field.name !== "real_id"
|
|
13473
|
+
).slice(0, previewFieldLimit).map((field) => `${field.name}=${formatScalar(field.value)}`).join(", ");
|
|
13381
13474
|
return preview ? `${headline}${pathLabel} [${classLabel}] ${preview}` : `${headline}${pathLabel} [${classLabel}]`;
|
|
13382
13475
|
}
|
|
13383
13476
|
function hashString(value) {
|
|
@@ -13393,7 +13486,9 @@ function hasSubstantiveAwaitAfterPrompt(code, marker) {
|
|
|
13393
13486
|
const startIndex = code.indexOf(marker);
|
|
13394
13487
|
if (startIndex === -1) return true;
|
|
13395
13488
|
const segment = code.slice(startIndex + marker.length);
|
|
13396
|
-
const callMatches = segment.matchAll(
|
|
13489
|
+
const callMatches = segment.matchAll(
|
|
13490
|
+
/await\s+([A-Za-z0-9_$.]+)\.([A-Za-z0-9_]+)\s*\(/g
|
|
13491
|
+
);
|
|
13397
13492
|
for (const match of callMatches) {
|
|
13398
13493
|
const receiver = match[1] || "";
|
|
13399
13494
|
const method = match[2] || "";
|
|
@@ -13425,9 +13520,16 @@ function reviewGeneratedJobCode(code) {
|
|
|
13425
13520
|
/approved\./i
|
|
13426
13521
|
];
|
|
13427
13522
|
if (normalized.includes("await loop.confirm(")) {
|
|
13428
|
-
const postConfirm = normalized.slice(
|
|
13429
|
-
|
|
13430
|
-
|
|
13523
|
+
const postConfirm = normalized.slice(
|
|
13524
|
+
normalized.indexOf("await loop.confirm(")
|
|
13525
|
+
);
|
|
13526
|
+
const hasPlaceholder = placeholderPatterns.some(
|
|
13527
|
+
(pattern) => pattern.test(postConfirm)
|
|
13528
|
+
);
|
|
13529
|
+
const hasSubstantiveAwait = hasSubstantiveAwaitAfterPrompt(
|
|
13530
|
+
normalized,
|
|
13531
|
+
"await loop.confirm("
|
|
13532
|
+
);
|
|
13431
13533
|
if (!hasSubstantiveAwait || hasPlaceholder) {
|
|
13432
13534
|
issues.push({
|
|
13433
13535
|
code: "placeholder_after_confirm",
|
|
@@ -13437,9 +13539,16 @@ function reviewGeneratedJobCode(code) {
|
|
|
13437
13539
|
}
|
|
13438
13540
|
}
|
|
13439
13541
|
if (normalized.includes("await loop.ask_user(")) {
|
|
13440
|
-
const postPrompt = normalized.slice(
|
|
13441
|
-
|
|
13442
|
-
|
|
13542
|
+
const postPrompt = normalized.slice(
|
|
13543
|
+
normalized.indexOf("await loop.ask_user(")
|
|
13544
|
+
);
|
|
13545
|
+
const hasPlaceholder = placeholderPatterns.some(
|
|
13546
|
+
(pattern) => pattern.test(postPrompt)
|
|
13547
|
+
);
|
|
13548
|
+
const hasSubstantiveAwait = hasSubstantiveAwaitAfterPrompt(
|
|
13549
|
+
normalized,
|
|
13550
|
+
"await loop.ask_user("
|
|
13551
|
+
);
|
|
13443
13552
|
if (hasPlaceholder && !hasSubstantiveAwait) {
|
|
13444
13553
|
issues.push({
|
|
13445
13554
|
code: "placeholder_after_ask_user",
|
|
@@ -13520,7 +13629,9 @@ function getLatestClosure(liveDoc) {
|
|
|
13520
13629
|
if (!record) continue;
|
|
13521
13630
|
closures.push({ ...record, closureId });
|
|
13522
13631
|
}
|
|
13523
|
-
closures.sort(
|
|
13632
|
+
closures.sort(
|
|
13633
|
+
(left, right) => (Number(right.createdAt) || 0) - (Number(left.createdAt) || 0)
|
|
13634
|
+
);
|
|
13524
13635
|
return closures[0] || null;
|
|
13525
13636
|
}
|
|
13526
13637
|
function getWorkflowBoundary(liveDoc, options) {
|
|
@@ -13558,7 +13669,9 @@ function getJobRecords(liveDoc) {
|
|
|
13558
13669
|
if (!record) continue;
|
|
13559
13670
|
jobs.push({ ...record, jobId });
|
|
13560
13671
|
}
|
|
13561
|
-
jobs.sort(
|
|
13672
|
+
jobs.sort(
|
|
13673
|
+
(left, right) => getJobTimestamp(right) - getJobTimestamp(left)
|
|
13674
|
+
);
|
|
13562
13675
|
return jobs;
|
|
13563
13676
|
}
|
|
13564
13677
|
function getPromptRecordsFromJobs(liveDoc) {
|
|
@@ -13566,7 +13679,9 @@ function getPromptRecordsFromJobs(liveDoc) {
|
|
|
13566
13679
|
}
|
|
13567
13680
|
function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
13568
13681
|
const boundary = getWorkflowBoundary(liveDoc, options);
|
|
13569
|
-
const jobs = getJobRecords(liveDoc).filter(
|
|
13682
|
+
const jobs = getJobRecords(liveDoc).filter(
|
|
13683
|
+
(job) => getJobTimestamp(job) >= boundary.timestamp
|
|
13684
|
+
).slice(0, 6).reverse();
|
|
13570
13685
|
const actionSummaryLines = [];
|
|
13571
13686
|
const variableNames = [];
|
|
13572
13687
|
const listNames = [];
|
|
@@ -13618,7 +13733,9 @@ function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
|
13618
13733
|
return updatedAt >= boundary.timestamp;
|
|
13619
13734
|
}
|
|
13620
13735
|
return status !== "completed" && status !== "canceled" ? true : updatedAt >= boundary.timestamp;
|
|
13621
|
-
}).sort(
|
|
13736
|
+
}).sort(
|
|
13737
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13738
|
+
);
|
|
13622
13739
|
for (const task of tasks.slice(0, 4)) {
|
|
13623
13740
|
if (typeof task.taskId === "string") {
|
|
13624
13741
|
activeTaskIds.push(task.taskId);
|
|
@@ -13630,7 +13747,9 @@ function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
|
13630
13747
|
return updatedAt >= boundary.timestamp;
|
|
13631
13748
|
}
|
|
13632
13749
|
return decision.status === "open" || updatedAt >= boundary.timestamp;
|
|
13633
|
-
}).sort(
|
|
13750
|
+
}).sort(
|
|
13751
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13752
|
+
);
|
|
13634
13753
|
for (const decision of decisions.slice(0, 3)) {
|
|
13635
13754
|
if (typeof decision.decisionId === "string" && decision.status === "open") {
|
|
13636
13755
|
openDecisionIds.push(decision.decisionId);
|
|
@@ -13709,11 +13828,15 @@ function projectWorkflowSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13709
13828
|
const lines = [];
|
|
13710
13829
|
lines.push("Workflow Boundary:");
|
|
13711
13830
|
if (focus.boundaryReason === "request_start") {
|
|
13712
|
-
lines.push(
|
|
13831
|
+
lines.push(
|
|
13832
|
+
"- Start from work recorded after the current user request began."
|
|
13833
|
+
);
|
|
13713
13834
|
} else if (focus.boundaryReason === "last_closed_loop" && focus.latestClosureId) {
|
|
13714
13835
|
lines.push(`- Start from work recorded after ${focus.latestClosureId}.`);
|
|
13715
13836
|
} else {
|
|
13716
|
-
lines.push(
|
|
13837
|
+
lines.push(
|
|
13838
|
+
"- No prior closed loop recorded; use the latest user request as the boundary."
|
|
13839
|
+
);
|
|
13717
13840
|
}
|
|
13718
13841
|
lines.push("", "Recent Actions:");
|
|
13719
13842
|
if (focus.recentActionSummary.length === 0) {
|
|
@@ -13782,12 +13905,17 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13782
13905
|
return updatedAt >= boundary.timestamp;
|
|
13783
13906
|
}
|
|
13784
13907
|
return status !== "completed" && status !== "canceled" ? true : updatedAt >= boundary.timestamp;
|
|
13785
|
-
}).sort(
|
|
13908
|
+
}).sort(
|
|
13909
|
+
(left, right) => (Number(right.updatedAt) || 0) - (Number(left.updatedAt) || 0)
|
|
13910
|
+
);
|
|
13786
13911
|
const activeTasks = tasks.filter((task) => {
|
|
13787
13912
|
const status = typeof task.status === "string" ? task.status : "pending";
|
|
13788
13913
|
return status !== "completed" && status !== "canceled";
|
|
13789
13914
|
});
|
|
13790
|
-
const visibleTasks = (activeTasks.length > 0 ? activeTasks : tasks).slice(
|
|
13915
|
+
const visibleTasks = (activeTasks.length > 0 ? activeTasks : tasks).slice(
|
|
13916
|
+
0,
|
|
13917
|
+
5
|
|
13918
|
+
);
|
|
13791
13919
|
const hiddenTaskCount = Math.max(0, activeTasks.length - visibleTasks.length);
|
|
13792
13920
|
lines.push("Tasks:");
|
|
13793
13921
|
if (visibleTasks.length === 0) {
|
|
@@ -13811,8 +13939,12 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13811
13939
|
return updatedAt >= boundary.timestamp;
|
|
13812
13940
|
}
|
|
13813
13941
|
return decision.status === "open" || updatedAt >= boundary.timestamp;
|
|
13814
|
-
}).sort(
|
|
13815
|
-
|
|
13942
|
+
}).sort(
|
|
13943
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13944
|
+
);
|
|
13945
|
+
const openDecisions = decisions.filter(
|
|
13946
|
+
(decision) => decision.status === "open"
|
|
13947
|
+
);
|
|
13816
13948
|
const visibleDecisions = (openDecisions.length > 0 ? openDecisions : decisions.slice(0, 1)).slice(0, 3);
|
|
13817
13949
|
lines.push("", "Recent Decisions:");
|
|
13818
13950
|
if (visibleDecisions.length === 0) {
|
|
@@ -13831,7 +13963,9 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13831
13963
|
const candidateLabel = typeof record.label === "string" && record.label.trim() ? record.label.trim() : candidateId;
|
|
13832
13964
|
return candidateLabel === candidateId ? candidateId : `${candidateLabel} (${candidateId})`;
|
|
13833
13965
|
}).filter((value) => Boolean(value)).join(", ");
|
|
13834
|
-
lines.push(
|
|
13966
|
+
lines.push(
|
|
13967
|
+
`- [open] ${title} (${decisionId})${candidatePreview ? ` \u2014 candidates: ${candidatePreview}` : ""}`
|
|
13968
|
+
);
|
|
13835
13969
|
} else {
|
|
13836
13970
|
const selected = asRecord2(decision.selected);
|
|
13837
13971
|
const label = typeof selected?.label === "string" ? selected.label : typeof selected?.id === "string" ? selected.id : "unknown";
|
|
@@ -13846,13 +13980,17 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13846
13980
|
title: prompt.title,
|
|
13847
13981
|
message: prompt.message
|
|
13848
13982
|
})),
|
|
13849
|
-
...Object.values(asRecord2(asRecord2(liveDoc?.jobs)?.byId) || {}).flatMap((job) => Object.values(asRecord2(asRecord2(job)?.prompts) || {})).map((prompt) => asRecord2(prompt)).filter(
|
|
13983
|
+
...Object.values(asRecord2(asRecord2(liveDoc?.jobs)?.byId) || {}).flatMap((job) => Object.values(asRecord2(asRecord2(job)?.prompts) || {})).map((prompt) => asRecord2(prompt)).filter(
|
|
13984
|
+
(prompt) => Boolean(prompt && prompt.status === "open")
|
|
13985
|
+
)
|
|
13850
13986
|
];
|
|
13851
13987
|
const visiblePrompts = boundary.reason === "request_start" ? openPrompts.filter((prompt) => {
|
|
13852
13988
|
const promptRecord = asRecord2(prompt);
|
|
13853
13989
|
const openedAt = Number(promptRecord?.openedAt) || 0;
|
|
13854
13990
|
const promptId = typeof promptRecord?.id === "string" ? promptRecord.id : typeof prompt.id === "string" ? prompt.id : null;
|
|
13855
|
-
return openedAt >= boundary.timestamp || (promptId ? pendingPrompts.some(
|
|
13991
|
+
return openedAt >= boundary.timestamp || (promptId ? pendingPrompts.some(
|
|
13992
|
+
(pendingPrompt) => pendingPrompt.id === promptId
|
|
13993
|
+
) : false);
|
|
13856
13994
|
}) : openPrompts;
|
|
13857
13995
|
lines.push("", "Open Prompts:");
|
|
13858
13996
|
if (visiblePrompts.length === 0) {
|
|
@@ -13883,9 +14021,15 @@ function projectHeapSummary(heap, options) {
|
|
|
13883
14021
|
const entriesByPath = asRecord2(heapRecord.entriesByPath) || {};
|
|
13884
14022
|
const listsByName = asRecord2(heapRecord.listsByName) || {};
|
|
13885
14023
|
const variablesByName = asRecord2(heapRecord.variablesByName) || {};
|
|
13886
|
-
const focusedVariableNames = new Set(
|
|
13887
|
-
|
|
13888
|
-
|
|
14024
|
+
const focusedVariableNames = new Set(
|
|
14025
|
+
uniqueStrings(options?.focus?.variableNames || [])
|
|
14026
|
+
);
|
|
14027
|
+
const focusedListNames = new Set(
|
|
14028
|
+
uniqueStrings(options?.focus?.listNames || [])
|
|
14029
|
+
);
|
|
14030
|
+
const focusedEntryPaths = new Set(
|
|
14031
|
+
uniqueStrings(options?.focus?.entryPaths || [])
|
|
14032
|
+
);
|
|
13889
14033
|
const hasFocus = focusedVariableNames.size > 0 || focusedListNames.size > 0 || focusedEntryPaths.size > 0;
|
|
13890
14034
|
const suppressRecentFallback = Boolean(options?.focus) && !hasFocus;
|
|
13891
14035
|
const maxVariables = options?.maxVariables ?? (hasFocus ? 4 : 6);
|
|
@@ -13897,20 +14041,26 @@ function projectHeapSummary(heap, options) {
|
|
|
13897
14041
|
return rightFocused - leftFocused || (right.updatedAt || 0) - (left.updatedAt || 0);
|
|
13898
14042
|
}).filter((variable, index) => {
|
|
13899
14043
|
if (index < maxVariables) return true;
|
|
13900
|
-
return Boolean(
|
|
14044
|
+
return Boolean(
|
|
14045
|
+
variable.name && focusedVariableNames.has(variable.name)
|
|
14046
|
+
);
|
|
13901
14047
|
}).slice(0, maxVariables);
|
|
13902
14048
|
const referencedPaths = /* @__PURE__ */ new Set();
|
|
13903
14049
|
for (const variable of variables) {
|
|
13904
14050
|
if (variable.entryPath) referencedPaths.add(variable.entryPath);
|
|
13905
14051
|
if (variable.listName) {
|
|
13906
|
-
const list = asRecord2(
|
|
14052
|
+
const list = asRecord2(
|
|
14053
|
+
listsByName[variable.listName]
|
|
14054
|
+
);
|
|
13907
14055
|
for (const path of list?.paths || []) referencedPaths.add(path);
|
|
13908
14056
|
}
|
|
13909
14057
|
}
|
|
13910
14058
|
for (const path of focusedEntryPaths) {
|
|
13911
14059
|
referencedPaths.add(path);
|
|
13912
14060
|
}
|
|
13913
|
-
const visibleLists = Object.values(listsByName).map((value) => asRecord2(value)).filter((value) => Boolean(value)).filter(
|
|
14061
|
+
const visibleLists = Object.values(listsByName).map((value) => asRecord2(value)).filter((value) => Boolean(value)).filter(
|
|
14062
|
+
(list) => variables.some((variable) => variable.listName === list.name) || Boolean(list.name && focusedListNames.has(list.name))
|
|
14063
|
+
).sort((left, right) => (right.updatedAt || 0) - (left.updatedAt || 0)).slice(0, maxLists);
|
|
13914
14064
|
const visibleEntries = Object.values(entriesByPath).map((value) => asRecord2(value)).filter((value) => Boolean(value)).filter((entry) => entry.path && referencedPaths.has(entry.path)).sort((left, right) => (right.updatedAt || 0) - (left.updatedAt || 0)).slice(0, maxEntries);
|
|
13915
14065
|
const lines = [];
|
|
13916
14066
|
lines.push("Variables:");
|
|
@@ -13919,16 +14069,24 @@ function projectHeapSummary(heap, options) {
|
|
|
13919
14069
|
} else {
|
|
13920
14070
|
for (const variable of variables) {
|
|
13921
14071
|
if (variable.kind === "scalar") {
|
|
13922
|
-
lines.push(
|
|
14072
|
+
lines.push(
|
|
14073
|
+
`- ${variable.name}: scalar = ${formatScalar(variable.value)}`
|
|
14074
|
+
);
|
|
13923
14075
|
continue;
|
|
13924
14076
|
}
|
|
13925
14077
|
if (variable.kind === "entry") {
|
|
13926
|
-
const entry = variable.entryPath ? asRecord2(
|
|
13927
|
-
|
|
14078
|
+
const entry = variable.entryPath ? asRecord2(
|
|
14079
|
+
entriesByPath[variable.entryPath]
|
|
14080
|
+
) : null;
|
|
14081
|
+
lines.push(
|
|
14082
|
+
`- ${variable.name}: entry<${variable.className || entry?.className || "unknown"}> -> ${entry ? describeHeapEntry(entry) : variable.entryPath || "missing"}`
|
|
14083
|
+
);
|
|
13928
14084
|
continue;
|
|
13929
14085
|
}
|
|
13930
14086
|
const list = variable.listName ? asRecord2(listsByName[variable.listName]) : null;
|
|
13931
|
-
lines.push(
|
|
14087
|
+
lines.push(
|
|
14088
|
+
`- ${variable.name}: list<${variable.className || list?.className || "unknown"}> -> ${(list?.paths || []).length} item(s)`
|
|
14089
|
+
);
|
|
13932
14090
|
}
|
|
13933
14091
|
}
|
|
13934
14092
|
lines.push("", "Named Lists:");
|
|
@@ -13936,7 +14094,9 @@ function projectHeapSummary(heap, options) {
|
|
|
13936
14094
|
lines.push("- none");
|
|
13937
14095
|
} else {
|
|
13938
14096
|
for (const list of visibleLists) {
|
|
13939
|
-
lines.push(
|
|
14097
|
+
lines.push(
|
|
14098
|
+
`- ${list.name}: ${list.className || "unknown"}[${(list.paths || []).length}]`
|
|
14099
|
+
);
|
|
13940
14100
|
}
|
|
13941
14101
|
}
|
|
13942
14102
|
lines.push("", "Active Entries:");
|
|
@@ -13950,11 +14110,19 @@ function projectHeapSummary(heap, options) {
|
|
|
13950
14110
|
return lines.join("\n");
|
|
13951
14111
|
}
|
|
13952
14112
|
function createHarnessVerifierSnapshot(input) {
|
|
13953
|
-
const workflowFocus = projectWorkflowFocus(
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
14113
|
+
const workflowFocus = projectWorkflowFocus(
|
|
14114
|
+
input.liveDoc,
|
|
14115
|
+
[],
|
|
14116
|
+
input.projectionOptions
|
|
14117
|
+
);
|
|
14118
|
+
const heapDigest = hashString(
|
|
14119
|
+
projectHeapSummary(asRecord2(input.liveDoc?.heap), {
|
|
14120
|
+
focus: workflowFocus
|
|
14121
|
+
})
|
|
14122
|
+
) || "00000000";
|
|
14123
|
+
const loopDigest = hashString(
|
|
14124
|
+
projectWorkflowSummary(input.liveDoc, [], input.projectionOptions)
|
|
14125
|
+
) || "00000000";
|
|
13958
14126
|
return {
|
|
13959
14127
|
codeDigest: hashString(input.finalCode?.trim()),
|
|
13960
14128
|
resultDigest: hashString(input.resultPreview?.trim()),
|
|
@@ -14084,8 +14252,12 @@ function buildGranularAgentToolBlock(tools) {
|
|
|
14084
14252
|
return "No live effects are available in this session yet.";
|
|
14085
14253
|
}
|
|
14086
14254
|
const globalTools = normalizedTools.filter((tool) => !tool.className);
|
|
14087
|
-
const staticTools = normalizedTools.filter(
|
|
14088
|
-
|
|
14255
|
+
const staticTools = normalizedTools.filter(
|
|
14256
|
+
(tool) => Boolean(tool.className && tool.static)
|
|
14257
|
+
);
|
|
14258
|
+
const instanceTools = normalizedTools.filter(
|
|
14259
|
+
(tool) => Boolean(tool.className && !tool.static)
|
|
14260
|
+
);
|
|
14089
14261
|
const lines = [
|
|
14090
14262
|
"Treat this block as the planning map. Use DOMAIN TYPES below for exact signatures."
|
|
14091
14263
|
];
|
|
@@ -14300,7 +14472,10 @@ ${loopBlock}
|
|
|
14300
14472
|
- Avoid \`as any\` and other broad casts when the DOMAIN TYPES block already tells you the correct class or list type.
|
|
14301
14473
|
- Prefer manipulating heap-backed instances and typed lists instead of returning raw JSON blobs or object IDs unless the user explicitly asks for them.
|
|
14302
14474
|
- If the user expects an answer after the job runs, the final \`return\` value must be either a short natural-language string or an object with a top-level \`reply\` string.
|
|
14475
|
+
- You may call \`agent_message(...)\` multiple times in one job to post several assistant messages while the job is still running.
|
|
14303
14476
|
- Prefer \`agent_message({ reply, show })\` when you want to leave a user-facing answer and optionally show heap-backed records in the UI.
|
|
14477
|
+
- \`agent_message(...)\` also accepts \`content\`, \`message\`, or \`text\` instead of \`reply\`.
|
|
14478
|
+
- \`agent_message({ show })\` may receive explicit refs or sandbox instances and arrays of sandbox instances. The runtime will convert those into UI references.
|
|
14304
14479
|
- When it helps the UI show specific heap-backed results, you may instead return:
|
|
14305
14480
|
\`{ reply: string, show: { entryPaths?: string[], listNames?: string[], variableNames?: string[] } }\`
|
|
14306
14481
|
- If you create or load objects the user should see, save them in the heap and return references to them through \`show\` instead of serializing full objects.
|