@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/agent-evals.js
CHANGED
|
@@ -4712,7 +4712,9 @@ var Session = class {
|
|
|
4712
4712
|
}
|
|
4713
4713
|
}
|
|
4714
4714
|
if (!revision) {
|
|
4715
|
-
throw new Error(
|
|
4715
|
+
throw new Error(
|
|
4716
|
+
"No domain revision available. Register live effects or ensure the build schema is activated."
|
|
4717
|
+
);
|
|
4716
4718
|
}
|
|
4717
4719
|
const result = await this.client.call("job.submit", {
|
|
4718
4720
|
domainRevision: revision,
|
|
@@ -4748,7 +4750,11 @@ var Session = class {
|
|
|
4748
4750
|
const prompt = this.promptCache.get(promptId);
|
|
4749
4751
|
const resolvedAnswer = resolvePromptAnswer(prompt, answer);
|
|
4750
4752
|
this.promptCache.delete(promptId);
|
|
4751
|
-
await this.client.call("prompt.answer", {
|
|
4753
|
+
await this.client.call("prompt.answer", {
|
|
4754
|
+
promptId,
|
|
4755
|
+
answer: resolvedAnswer,
|
|
4756
|
+
value: resolvedAnswer
|
|
4757
|
+
});
|
|
4752
4758
|
}
|
|
4753
4759
|
/**
|
|
4754
4760
|
* Get the current list of available effects.
|
|
@@ -4780,7 +4786,8 @@ var Session = class {
|
|
|
4780
4786
|
for (const tool of cat.tools) {
|
|
4781
4787
|
if (!tool?.name) continue;
|
|
4782
4788
|
const existing = toolMap.get(tool.name);
|
|
4783
|
-
if (existing?.publishedAt && cat.publishedAt && existing.publishedAt > cat.publishedAt)
|
|
4789
|
+
if (existing?.publishedAt && cat.publishedAt && existing.publishedAt > cat.publishedAt)
|
|
4790
|
+
continue;
|
|
4784
4791
|
const isLocal = clientId === this.clientId;
|
|
4785
4792
|
const ready = isLocal ? this.effects.has(tool.name) || this.toolHandlers.has(tool.name) || this.instanceTools.has(tool.name) : true;
|
|
4786
4793
|
toolMap.set(tool.name, {
|
|
@@ -4818,7 +4825,10 @@ var Session = class {
|
|
|
4818
4825
|
return () => {
|
|
4819
4826
|
const listeners = this.eventListeners.get("effects:changed");
|
|
4820
4827
|
if (listeners) {
|
|
4821
|
-
this.eventListeners.set(
|
|
4828
|
+
this.eventListeners.set(
|
|
4829
|
+
"effects:changed",
|
|
4830
|
+
listeners.filter((h) => h !== handler)
|
|
4831
|
+
);
|
|
4822
4832
|
}
|
|
4823
4833
|
};
|
|
4824
4834
|
}
|
|
@@ -4834,7 +4844,10 @@ var Session = class {
|
|
|
4834
4844
|
return () => {
|
|
4835
4845
|
const listeners = this.eventListeners.get("tools:changed");
|
|
4836
4846
|
if (listeners) {
|
|
4837
|
-
this.eventListeners.set(
|
|
4847
|
+
this.eventListeners.set(
|
|
4848
|
+
"tools:changed",
|
|
4849
|
+
listeners.filter((h) => h !== handler)
|
|
4850
|
+
);
|
|
4838
4851
|
}
|
|
4839
4852
|
};
|
|
4840
4853
|
}
|
|
@@ -4842,11 +4855,16 @@ var Session = class {
|
|
|
4842
4855
|
* Get the current domain state and available tools
|
|
4843
4856
|
*/
|
|
4844
4857
|
async getDomain() {
|
|
4845
|
-
const summary = await this.client.call(
|
|
4858
|
+
const summary = await this.client.call(
|
|
4859
|
+
"domain.getSummary",
|
|
4860
|
+
{}
|
|
4861
|
+
);
|
|
4846
4862
|
if (summary.activeDomainRevision) {
|
|
4847
4863
|
this.currentDomainRevision = summary.activeDomainRevision;
|
|
4848
4864
|
} else {
|
|
4849
|
-
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
4865
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
4866
|
+
this.client.doc
|
|
4867
|
+
);
|
|
4850
4868
|
}
|
|
4851
4869
|
return summary;
|
|
4852
4870
|
}
|
|
@@ -5021,20 +5039,31 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5021
5039
|
off(event, handler) {
|
|
5022
5040
|
const handlers = this.eventListeners.get(event);
|
|
5023
5041
|
if (handlers) {
|
|
5024
|
-
this.eventListeners.set(
|
|
5042
|
+
this.eventListeners.set(
|
|
5043
|
+
event,
|
|
5044
|
+
handlers.filter((h) => h !== handler)
|
|
5045
|
+
);
|
|
5025
5046
|
}
|
|
5026
5047
|
}
|
|
5027
5048
|
// --- Internal ---
|
|
5028
5049
|
setupToolInvokeHandler() {
|
|
5029
5050
|
this.client.registerRpcHandler("tool.invoke", async (params) => {
|
|
5030
5051
|
const { callId, toolName, input } = params;
|
|
5031
|
-
this.emit("effect:invoke", {
|
|
5052
|
+
this.emit("effect:invoke", {
|
|
5053
|
+
callId,
|
|
5054
|
+
effectKey: toolName,
|
|
5055
|
+
toolName,
|
|
5056
|
+
input
|
|
5057
|
+
});
|
|
5032
5058
|
this.emit("tool:invoke", { callId, toolName, input });
|
|
5033
5059
|
const handler = this.toolHandlers.get(toolName);
|
|
5034
5060
|
if (!handler) {
|
|
5035
5061
|
await this.client.call("tool.result", {
|
|
5036
5062
|
callId,
|
|
5037
|
-
error: {
|
|
5063
|
+
error: {
|
|
5064
|
+
code: "TOOL_NOT_FOUND",
|
|
5065
|
+
message: `Tool handler not found: ${toolName}`
|
|
5066
|
+
}
|
|
5038
5067
|
});
|
|
5039
5068
|
return;
|
|
5040
5069
|
}
|
|
@@ -5043,7 +5072,11 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5043
5072
|
const invocationContext = this.buildLegacyEffectContext();
|
|
5044
5073
|
if (this.instanceTools.has(toolName) && input && typeof input === "object" && "_objectId" in input) {
|
|
5045
5074
|
const { _objectId, ...restParams } = input;
|
|
5046
|
-
result = await handler(
|
|
5075
|
+
result = await handler(
|
|
5076
|
+
_objectId,
|
|
5077
|
+
restParams,
|
|
5078
|
+
invocationContext
|
|
5079
|
+
);
|
|
5047
5080
|
} else {
|
|
5048
5081
|
result = await handler(input, invocationContext);
|
|
5049
5082
|
}
|
|
@@ -5055,7 +5088,11 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5055
5088
|
});
|
|
5056
5089
|
} catch (error) {
|
|
5057
5090
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5058
|
-
this.emit("effect:result", {
|
|
5091
|
+
this.emit("effect:result", {
|
|
5092
|
+
callId,
|
|
5093
|
+
effectKey: toolName,
|
|
5094
|
+
error: errorMessage
|
|
5095
|
+
});
|
|
5059
5096
|
this.emit("tool:result", { callId, error: errorMessage });
|
|
5060
5097
|
await this.client.call("tool.result", {
|
|
5061
5098
|
callId,
|
|
@@ -5065,7 +5102,10 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5065
5102
|
});
|
|
5066
5103
|
}
|
|
5067
5104
|
setupEventHandlers() {
|
|
5068
|
-
this.client.on(
|
|
5105
|
+
this.client.on(
|
|
5106
|
+
"open",
|
|
5107
|
+
(payload) => this.emit("open", payload || {})
|
|
5108
|
+
);
|
|
5069
5109
|
this.client.on("sync", (doc) => {
|
|
5070
5110
|
this.currentDomainRevision = this.extractDomainRevisionFromDoc(doc);
|
|
5071
5111
|
this.emit("sync", doc);
|
|
@@ -5079,8 +5119,14 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5079
5119
|
};
|
|
5080
5120
|
this.client.on("prompt", emitPrompt);
|
|
5081
5121
|
this.client.on("prompt.request", emitPrompt);
|
|
5082
|
-
this.client.on(
|
|
5083
|
-
|
|
5122
|
+
this.client.on(
|
|
5123
|
+
"disconnect",
|
|
5124
|
+
(payload) => this.emit("disconnect", payload || {})
|
|
5125
|
+
);
|
|
5126
|
+
this.client.on(
|
|
5127
|
+
"reconnect_error",
|
|
5128
|
+
(payload) => this.emit("reconnect_error", payload || {})
|
|
5129
|
+
);
|
|
5084
5130
|
this.client.on("job.status", (data) => {
|
|
5085
5131
|
this.emit("job:status", data);
|
|
5086
5132
|
});
|
|
@@ -5196,7 +5242,10 @@ function sanitizeFeedbackValue(value, depth = 0, seen = /* @__PURE__ */ new Weak
|
|
|
5196
5242
|
return "[Circular]";
|
|
5197
5243
|
}
|
|
5198
5244
|
seen.add(value);
|
|
5199
|
-
const entries = Object.entries(value).slice(
|
|
5245
|
+
const entries = Object.entries(value).slice(
|
|
5246
|
+
0,
|
|
5247
|
+
MAX_FEEDBACK_OBJECT_KEYS
|
|
5248
|
+
);
|
|
5200
5249
|
const sanitized = {};
|
|
5201
5250
|
for (const [key, entryValue] of entries) {
|
|
5202
5251
|
sanitized[key] = sanitizeFeedbackValue(entryValue, depth + 1, seen);
|
|
@@ -5247,12 +5296,18 @@ var JobImplementation = class {
|
|
|
5247
5296
|
if (progressData.execId === id || progressData.jobId === id) {
|
|
5248
5297
|
if (progressData.stdout) {
|
|
5249
5298
|
this.markStarted();
|
|
5250
|
-
this.metadata.stdout = [
|
|
5299
|
+
this.metadata.stdout = [
|
|
5300
|
+
...this.metadata.stdout,
|
|
5301
|
+
truncateFeedbackString(progressData.stdout)
|
|
5302
|
+
].slice(-100);
|
|
5251
5303
|
this.emit("stdout", progressData.stdout);
|
|
5252
5304
|
}
|
|
5253
5305
|
if (progressData.stderr) {
|
|
5254
5306
|
this.markStarted();
|
|
5255
|
-
this.metadata.stderr = [
|
|
5307
|
+
this.metadata.stderr = [
|
|
5308
|
+
...this.metadata.stderr,
|
|
5309
|
+
truncateFeedbackString(progressData.stderr)
|
|
5310
|
+
].slice(-100);
|
|
5256
5311
|
this.emit("stderr", progressData.stderr);
|
|
5257
5312
|
}
|
|
5258
5313
|
}
|
|
@@ -5274,12 +5329,18 @@ var JobImplementation = class {
|
|
|
5274
5329
|
});
|
|
5275
5330
|
this.client.on(`job.${id}.stdout`, (line) => {
|
|
5276
5331
|
this.markStarted();
|
|
5277
|
-
this.metadata.stdout = [
|
|
5332
|
+
this.metadata.stdout = [
|
|
5333
|
+
...this.metadata.stdout,
|
|
5334
|
+
truncateFeedbackString(String(line))
|
|
5335
|
+
].slice(-100);
|
|
5278
5336
|
this.emit("stdout", line);
|
|
5279
5337
|
});
|
|
5280
5338
|
this.client.on(`job.${id}.stderr`, (line) => {
|
|
5281
5339
|
this.markStarted();
|
|
5282
|
-
this.metadata.stderr = [
|
|
5340
|
+
this.metadata.stderr = [
|
|
5341
|
+
...this.metadata.stderr,
|
|
5342
|
+
truncateFeedbackString(String(line))
|
|
5343
|
+
].slice(-100);
|
|
5283
5344
|
this.emit("stderr", line);
|
|
5284
5345
|
});
|
|
5285
5346
|
this.client.on(`job.${id}.result`, (result) => {
|
|
@@ -5311,7 +5372,11 @@ var JobImplementation = class {
|
|
|
5311
5372
|
this.client.on("job.failed", (data) => {
|
|
5312
5373
|
const jobData = data;
|
|
5313
5374
|
if (jobData.jobId === id) {
|
|
5314
|
-
this.finalize(
|
|
5375
|
+
this.finalize(
|
|
5376
|
+
"failed",
|
|
5377
|
+
void 0,
|
|
5378
|
+
jobData.error || new Error("Job failed")
|
|
5379
|
+
);
|
|
5315
5380
|
this.emit("status", this.status);
|
|
5316
5381
|
}
|
|
5317
5382
|
});
|
|
@@ -5324,7 +5389,12 @@ var JobImplementation = class {
|
|
|
5324
5389
|
input: sanitizeFeedbackValue(d.input),
|
|
5325
5390
|
startedAt: d.timestamp || Date.now()
|
|
5326
5391
|
});
|
|
5327
|
-
this.emit("toolCallStart", {
|
|
5392
|
+
this.emit("toolCallStart", {
|
|
5393
|
+
callId: d.callId,
|
|
5394
|
+
toolName: d.toolName,
|
|
5395
|
+
input: d.input,
|
|
5396
|
+
timestamp: d.timestamp
|
|
5397
|
+
});
|
|
5328
5398
|
}
|
|
5329
5399
|
});
|
|
5330
5400
|
this.client.on("tool.call.end", (data) => {
|
|
@@ -5339,7 +5409,25 @@ var JobImplementation = class {
|
|
|
5339
5409
|
completedAt,
|
|
5340
5410
|
durationMs: typeof d.durationMs === "number" ? d.durationMs : void 0
|
|
5341
5411
|
});
|
|
5342
|
-
this.emit("toolCallEnd", {
|
|
5412
|
+
this.emit("toolCallEnd", {
|
|
5413
|
+
callId: d.callId,
|
|
5414
|
+
toolName: d.toolName,
|
|
5415
|
+
result: d.result,
|
|
5416
|
+
error: d.error,
|
|
5417
|
+
durationMs: d.durationMs,
|
|
5418
|
+
timestamp: d.timestamp
|
|
5419
|
+
});
|
|
5420
|
+
}
|
|
5421
|
+
});
|
|
5422
|
+
this.client.on("job.agent_message", (data) => {
|
|
5423
|
+
const d = data;
|
|
5424
|
+
if (d.jobId === id) {
|
|
5425
|
+
this.emit("agentMessage", {
|
|
5426
|
+
messageId: d.messageId,
|
|
5427
|
+
reply: typeof d.reply === "string" ? d.reply : "",
|
|
5428
|
+
show: d.show,
|
|
5429
|
+
timestamp: d.timestamp || Date.now()
|
|
5430
|
+
});
|
|
5343
5431
|
}
|
|
5344
5432
|
});
|
|
5345
5433
|
}
|
|
@@ -5409,7 +5497,9 @@ var JobImplementation = class {
|
|
|
5409
5497
|
}
|
|
5410
5498
|
upsertToolCall(next) {
|
|
5411
5499
|
const callId = next.callId || `tool-call-${Date.now()}`;
|
|
5412
|
-
const existingIndex = this.metadata.toolCalls.findIndex(
|
|
5500
|
+
const existingIndex = this.metadata.toolCalls.findIndex(
|
|
5501
|
+
(entry) => entry.callId === callId
|
|
5502
|
+
);
|
|
5413
5503
|
const existing = existingIndex >= 0 ? this.metadata.toolCalls[existingIndex] : void 0;
|
|
5414
5504
|
const merged = {
|
|
5415
5505
|
...existing,
|
|
@@ -13374,7 +13464,8 @@ function uniqueStrings(values, maxCount) {
|
|
|
13374
13464
|
}
|
|
13375
13465
|
function formatScalar(value) {
|
|
13376
13466
|
if (typeof value === "string") return JSON.stringify(value);
|
|
13377
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
13467
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
13468
|
+
return String(value);
|
|
13378
13469
|
if (value === null) return "null";
|
|
13379
13470
|
return "unknown";
|
|
13380
13471
|
}
|
|
@@ -13382,7 +13473,9 @@ function describeHeapEntry(entry, previewFieldLimit = 3) {
|
|
|
13382
13473
|
const headline = entry.label || entry.id || entry.path || "Unknown";
|
|
13383
13474
|
const pathLabel = entry.path && entry.path !== headline ? ` <${entry.path}>` : "";
|
|
13384
13475
|
const classLabel = entry.className || "unknown";
|
|
13385
|
-
const preview = asArray(entry.fields).filter(
|
|
13476
|
+
const preview = asArray(entry.fields).filter(
|
|
13477
|
+
(field) => field?.name && field.name !== "_realId" && field.name !== "real_id"
|
|
13478
|
+
).slice(0, previewFieldLimit).map((field) => `${field.name}=${formatScalar(field.value)}`).join(", ");
|
|
13386
13479
|
return preview ? `${headline}${pathLabel} [${classLabel}] ${preview}` : `${headline}${pathLabel} [${classLabel}]`;
|
|
13387
13480
|
}
|
|
13388
13481
|
function hashString(value) {
|
|
@@ -13398,7 +13491,9 @@ function hasSubstantiveAwaitAfterPrompt(code, marker) {
|
|
|
13398
13491
|
const startIndex = code.indexOf(marker);
|
|
13399
13492
|
if (startIndex === -1) return true;
|
|
13400
13493
|
const segment = code.slice(startIndex + marker.length);
|
|
13401
|
-
const callMatches = segment.matchAll(
|
|
13494
|
+
const callMatches = segment.matchAll(
|
|
13495
|
+
/await\s+([A-Za-z0-9_$.]+)\.([A-Za-z0-9_]+)\s*\(/g
|
|
13496
|
+
);
|
|
13402
13497
|
for (const match of callMatches) {
|
|
13403
13498
|
const receiver = match[1] || "";
|
|
13404
13499
|
const method = match[2] || "";
|
|
@@ -13430,9 +13525,16 @@ function reviewGeneratedJobCode(code) {
|
|
|
13430
13525
|
/approved\./i
|
|
13431
13526
|
];
|
|
13432
13527
|
if (normalized.includes("await loop.confirm(")) {
|
|
13433
|
-
const postConfirm = normalized.slice(
|
|
13434
|
-
|
|
13435
|
-
|
|
13528
|
+
const postConfirm = normalized.slice(
|
|
13529
|
+
normalized.indexOf("await loop.confirm(")
|
|
13530
|
+
);
|
|
13531
|
+
const hasPlaceholder = placeholderPatterns.some(
|
|
13532
|
+
(pattern) => pattern.test(postConfirm)
|
|
13533
|
+
);
|
|
13534
|
+
const hasSubstantiveAwait = hasSubstantiveAwaitAfterPrompt(
|
|
13535
|
+
normalized,
|
|
13536
|
+
"await loop.confirm("
|
|
13537
|
+
);
|
|
13436
13538
|
if (!hasSubstantiveAwait || hasPlaceholder) {
|
|
13437
13539
|
issues.push({
|
|
13438
13540
|
code: "placeholder_after_confirm",
|
|
@@ -13442,9 +13544,16 @@ function reviewGeneratedJobCode(code) {
|
|
|
13442
13544
|
}
|
|
13443
13545
|
}
|
|
13444
13546
|
if (normalized.includes("await loop.ask_user(")) {
|
|
13445
|
-
const postPrompt = normalized.slice(
|
|
13446
|
-
|
|
13447
|
-
|
|
13547
|
+
const postPrompt = normalized.slice(
|
|
13548
|
+
normalized.indexOf("await loop.ask_user(")
|
|
13549
|
+
);
|
|
13550
|
+
const hasPlaceholder = placeholderPatterns.some(
|
|
13551
|
+
(pattern) => pattern.test(postPrompt)
|
|
13552
|
+
);
|
|
13553
|
+
const hasSubstantiveAwait = hasSubstantiveAwaitAfterPrompt(
|
|
13554
|
+
normalized,
|
|
13555
|
+
"await loop.ask_user("
|
|
13556
|
+
);
|
|
13448
13557
|
if (hasPlaceholder && !hasSubstantiveAwait) {
|
|
13449
13558
|
issues.push({
|
|
13450
13559
|
code: "placeholder_after_ask_user",
|
|
@@ -13525,7 +13634,9 @@ function getLatestClosure(liveDoc) {
|
|
|
13525
13634
|
if (!record) continue;
|
|
13526
13635
|
closures.push({ ...record, closureId });
|
|
13527
13636
|
}
|
|
13528
|
-
closures.sort(
|
|
13637
|
+
closures.sort(
|
|
13638
|
+
(left, right) => (Number(right.createdAt) || 0) - (Number(left.createdAt) || 0)
|
|
13639
|
+
);
|
|
13529
13640
|
return closures[0] || null;
|
|
13530
13641
|
}
|
|
13531
13642
|
function getWorkflowBoundary(liveDoc, options) {
|
|
@@ -13563,7 +13674,9 @@ function getJobRecords(liveDoc) {
|
|
|
13563
13674
|
if (!record) continue;
|
|
13564
13675
|
jobs.push({ ...record, jobId });
|
|
13565
13676
|
}
|
|
13566
|
-
jobs.sort(
|
|
13677
|
+
jobs.sort(
|
|
13678
|
+
(left, right) => getJobTimestamp(right) - getJobTimestamp(left)
|
|
13679
|
+
);
|
|
13567
13680
|
return jobs;
|
|
13568
13681
|
}
|
|
13569
13682
|
function getPromptRecordsFromJobs(liveDoc) {
|
|
@@ -13571,7 +13684,9 @@ function getPromptRecordsFromJobs(liveDoc) {
|
|
|
13571
13684
|
}
|
|
13572
13685
|
function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
13573
13686
|
const boundary = getWorkflowBoundary(liveDoc, options);
|
|
13574
|
-
const jobs = getJobRecords(liveDoc).filter(
|
|
13687
|
+
const jobs = getJobRecords(liveDoc).filter(
|
|
13688
|
+
(job) => getJobTimestamp(job) >= boundary.timestamp
|
|
13689
|
+
).slice(0, 6).reverse();
|
|
13575
13690
|
const actionSummaryLines = [];
|
|
13576
13691
|
const variableNames = [];
|
|
13577
13692
|
const listNames = [];
|
|
@@ -13623,7 +13738,9 @@ function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
|
13623
13738
|
return updatedAt >= boundary.timestamp;
|
|
13624
13739
|
}
|
|
13625
13740
|
return status !== "completed" && status !== "canceled" ? true : updatedAt >= boundary.timestamp;
|
|
13626
|
-
}).sort(
|
|
13741
|
+
}).sort(
|
|
13742
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13743
|
+
);
|
|
13627
13744
|
for (const task of tasks.slice(0, 4)) {
|
|
13628
13745
|
if (typeof task.taskId === "string") {
|
|
13629
13746
|
activeTaskIds.push(task.taskId);
|
|
@@ -13635,7 +13752,9 @@ function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
|
13635
13752
|
return updatedAt >= boundary.timestamp;
|
|
13636
13753
|
}
|
|
13637
13754
|
return decision.status === "open" || updatedAt >= boundary.timestamp;
|
|
13638
|
-
}).sort(
|
|
13755
|
+
}).sort(
|
|
13756
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13757
|
+
);
|
|
13639
13758
|
for (const decision of decisions.slice(0, 3)) {
|
|
13640
13759
|
if (typeof decision.decisionId === "string" && decision.status === "open") {
|
|
13641
13760
|
openDecisionIds.push(decision.decisionId);
|
|
@@ -13714,11 +13833,15 @@ function projectWorkflowSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13714
13833
|
const lines = [];
|
|
13715
13834
|
lines.push("Workflow Boundary:");
|
|
13716
13835
|
if (focus.boundaryReason === "request_start") {
|
|
13717
|
-
lines.push(
|
|
13836
|
+
lines.push(
|
|
13837
|
+
"- Start from work recorded after the current user request began."
|
|
13838
|
+
);
|
|
13718
13839
|
} else if (focus.boundaryReason === "last_closed_loop" && focus.latestClosureId) {
|
|
13719
13840
|
lines.push(`- Start from work recorded after ${focus.latestClosureId}.`);
|
|
13720
13841
|
} else {
|
|
13721
|
-
lines.push(
|
|
13842
|
+
lines.push(
|
|
13843
|
+
"- No prior closed loop recorded; use the latest user request as the boundary."
|
|
13844
|
+
);
|
|
13722
13845
|
}
|
|
13723
13846
|
lines.push("", "Recent Actions:");
|
|
13724
13847
|
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 path2 of list?.paths || []) referencedPaths.add(path2);
|
|
13908
14056
|
}
|
|
13909
14057
|
}
|
|
13910
14058
|
for (const path2 of focusedEntryPaths) {
|
|
13911
14059
|
referencedPaths.add(path2);
|
|
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.
|