@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.mjs
CHANGED
|
@@ -4687,7 +4687,9 @@ var Session = class {
|
|
|
4687
4687
|
}
|
|
4688
4688
|
}
|
|
4689
4689
|
if (!revision) {
|
|
4690
|
-
throw new Error(
|
|
4690
|
+
throw new Error(
|
|
4691
|
+
"No domain revision available. Register live effects or ensure the build schema is activated."
|
|
4692
|
+
);
|
|
4691
4693
|
}
|
|
4692
4694
|
const result = await this.client.call("job.submit", {
|
|
4693
4695
|
domainRevision: revision,
|
|
@@ -4723,7 +4725,11 @@ var Session = class {
|
|
|
4723
4725
|
const prompt = this.promptCache.get(promptId);
|
|
4724
4726
|
const resolvedAnswer = resolvePromptAnswer(prompt, answer);
|
|
4725
4727
|
this.promptCache.delete(promptId);
|
|
4726
|
-
await this.client.call("prompt.answer", {
|
|
4728
|
+
await this.client.call("prompt.answer", {
|
|
4729
|
+
promptId,
|
|
4730
|
+
answer: resolvedAnswer,
|
|
4731
|
+
value: resolvedAnswer
|
|
4732
|
+
});
|
|
4727
4733
|
}
|
|
4728
4734
|
/**
|
|
4729
4735
|
* Get the current list of available effects.
|
|
@@ -4755,7 +4761,8 @@ var Session = class {
|
|
|
4755
4761
|
for (const tool of cat.tools) {
|
|
4756
4762
|
if (!tool?.name) continue;
|
|
4757
4763
|
const existing = toolMap.get(tool.name);
|
|
4758
|
-
if (existing?.publishedAt && cat.publishedAt && existing.publishedAt > cat.publishedAt)
|
|
4764
|
+
if (existing?.publishedAt && cat.publishedAt && existing.publishedAt > cat.publishedAt)
|
|
4765
|
+
continue;
|
|
4759
4766
|
const isLocal = clientId === this.clientId;
|
|
4760
4767
|
const ready = isLocal ? this.effects.has(tool.name) || this.toolHandlers.has(tool.name) || this.instanceTools.has(tool.name) : true;
|
|
4761
4768
|
toolMap.set(tool.name, {
|
|
@@ -4793,7 +4800,10 @@ var Session = class {
|
|
|
4793
4800
|
return () => {
|
|
4794
4801
|
const listeners = this.eventListeners.get("effects:changed");
|
|
4795
4802
|
if (listeners) {
|
|
4796
|
-
this.eventListeners.set(
|
|
4803
|
+
this.eventListeners.set(
|
|
4804
|
+
"effects:changed",
|
|
4805
|
+
listeners.filter((h) => h !== handler)
|
|
4806
|
+
);
|
|
4797
4807
|
}
|
|
4798
4808
|
};
|
|
4799
4809
|
}
|
|
@@ -4809,7 +4819,10 @@ var Session = class {
|
|
|
4809
4819
|
return () => {
|
|
4810
4820
|
const listeners = this.eventListeners.get("tools:changed");
|
|
4811
4821
|
if (listeners) {
|
|
4812
|
-
this.eventListeners.set(
|
|
4822
|
+
this.eventListeners.set(
|
|
4823
|
+
"tools:changed",
|
|
4824
|
+
listeners.filter((h) => h !== handler)
|
|
4825
|
+
);
|
|
4813
4826
|
}
|
|
4814
4827
|
};
|
|
4815
4828
|
}
|
|
@@ -4817,11 +4830,16 @@ var Session = class {
|
|
|
4817
4830
|
* Get the current domain state and available tools
|
|
4818
4831
|
*/
|
|
4819
4832
|
async getDomain() {
|
|
4820
|
-
const summary = await this.client.call(
|
|
4833
|
+
const summary = await this.client.call(
|
|
4834
|
+
"domain.getSummary",
|
|
4835
|
+
{}
|
|
4836
|
+
);
|
|
4821
4837
|
if (summary.activeDomainRevision) {
|
|
4822
4838
|
this.currentDomainRevision = summary.activeDomainRevision;
|
|
4823
4839
|
} else {
|
|
4824
|
-
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
4840
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
4841
|
+
this.client.doc
|
|
4842
|
+
);
|
|
4825
4843
|
}
|
|
4826
4844
|
return summary;
|
|
4827
4845
|
}
|
|
@@ -4996,20 +5014,31 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4996
5014
|
off(event, handler) {
|
|
4997
5015
|
const handlers = this.eventListeners.get(event);
|
|
4998
5016
|
if (handlers) {
|
|
4999
|
-
this.eventListeners.set(
|
|
5017
|
+
this.eventListeners.set(
|
|
5018
|
+
event,
|
|
5019
|
+
handlers.filter((h) => h !== handler)
|
|
5020
|
+
);
|
|
5000
5021
|
}
|
|
5001
5022
|
}
|
|
5002
5023
|
// --- Internal ---
|
|
5003
5024
|
setupToolInvokeHandler() {
|
|
5004
5025
|
this.client.registerRpcHandler("tool.invoke", async (params) => {
|
|
5005
5026
|
const { callId, toolName, input } = params;
|
|
5006
|
-
this.emit("effect:invoke", {
|
|
5027
|
+
this.emit("effect:invoke", {
|
|
5028
|
+
callId,
|
|
5029
|
+
effectKey: toolName,
|
|
5030
|
+
toolName,
|
|
5031
|
+
input
|
|
5032
|
+
});
|
|
5007
5033
|
this.emit("tool:invoke", { callId, toolName, input });
|
|
5008
5034
|
const handler = this.toolHandlers.get(toolName);
|
|
5009
5035
|
if (!handler) {
|
|
5010
5036
|
await this.client.call("tool.result", {
|
|
5011
5037
|
callId,
|
|
5012
|
-
error: {
|
|
5038
|
+
error: {
|
|
5039
|
+
code: "TOOL_NOT_FOUND",
|
|
5040
|
+
message: `Tool handler not found: ${toolName}`
|
|
5041
|
+
}
|
|
5013
5042
|
});
|
|
5014
5043
|
return;
|
|
5015
5044
|
}
|
|
@@ -5018,7 +5047,11 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5018
5047
|
const invocationContext = this.buildLegacyEffectContext();
|
|
5019
5048
|
if (this.instanceTools.has(toolName) && input && typeof input === "object" && "_objectId" in input) {
|
|
5020
5049
|
const { _objectId, ...restParams } = input;
|
|
5021
|
-
result = await handler(
|
|
5050
|
+
result = await handler(
|
|
5051
|
+
_objectId,
|
|
5052
|
+
restParams,
|
|
5053
|
+
invocationContext
|
|
5054
|
+
);
|
|
5022
5055
|
} else {
|
|
5023
5056
|
result = await handler(input, invocationContext);
|
|
5024
5057
|
}
|
|
@@ -5030,7 +5063,11 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5030
5063
|
});
|
|
5031
5064
|
} catch (error) {
|
|
5032
5065
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5033
|
-
this.emit("effect:result", {
|
|
5066
|
+
this.emit("effect:result", {
|
|
5067
|
+
callId,
|
|
5068
|
+
effectKey: toolName,
|
|
5069
|
+
error: errorMessage
|
|
5070
|
+
});
|
|
5034
5071
|
this.emit("tool:result", { callId, error: errorMessage });
|
|
5035
5072
|
await this.client.call("tool.result", {
|
|
5036
5073
|
callId,
|
|
@@ -5040,7 +5077,10 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5040
5077
|
});
|
|
5041
5078
|
}
|
|
5042
5079
|
setupEventHandlers() {
|
|
5043
|
-
this.client.on(
|
|
5080
|
+
this.client.on(
|
|
5081
|
+
"open",
|
|
5082
|
+
(payload) => this.emit("open", payload || {})
|
|
5083
|
+
);
|
|
5044
5084
|
this.client.on("sync", (doc) => {
|
|
5045
5085
|
this.currentDomainRevision = this.extractDomainRevisionFromDoc(doc);
|
|
5046
5086
|
this.emit("sync", doc);
|
|
@@ -5054,8 +5094,14 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5054
5094
|
};
|
|
5055
5095
|
this.client.on("prompt", emitPrompt);
|
|
5056
5096
|
this.client.on("prompt.request", emitPrompt);
|
|
5057
|
-
this.client.on(
|
|
5058
|
-
|
|
5097
|
+
this.client.on(
|
|
5098
|
+
"disconnect",
|
|
5099
|
+
(payload) => this.emit("disconnect", payload || {})
|
|
5100
|
+
);
|
|
5101
|
+
this.client.on(
|
|
5102
|
+
"reconnect_error",
|
|
5103
|
+
(payload) => this.emit("reconnect_error", payload || {})
|
|
5104
|
+
);
|
|
5059
5105
|
this.client.on("job.status", (data) => {
|
|
5060
5106
|
this.emit("job:status", data);
|
|
5061
5107
|
});
|
|
@@ -5171,7 +5217,10 @@ function sanitizeFeedbackValue(value, depth = 0, seen = /* @__PURE__ */ new Weak
|
|
|
5171
5217
|
return "[Circular]";
|
|
5172
5218
|
}
|
|
5173
5219
|
seen.add(value);
|
|
5174
|
-
const entries = Object.entries(value).slice(
|
|
5220
|
+
const entries = Object.entries(value).slice(
|
|
5221
|
+
0,
|
|
5222
|
+
MAX_FEEDBACK_OBJECT_KEYS
|
|
5223
|
+
);
|
|
5175
5224
|
const sanitized = {};
|
|
5176
5225
|
for (const [key, entryValue] of entries) {
|
|
5177
5226
|
sanitized[key] = sanitizeFeedbackValue(entryValue, depth + 1, seen);
|
|
@@ -5222,12 +5271,18 @@ var JobImplementation = class {
|
|
|
5222
5271
|
if (progressData.execId === id || progressData.jobId === id) {
|
|
5223
5272
|
if (progressData.stdout) {
|
|
5224
5273
|
this.markStarted();
|
|
5225
|
-
this.metadata.stdout = [
|
|
5274
|
+
this.metadata.stdout = [
|
|
5275
|
+
...this.metadata.stdout,
|
|
5276
|
+
truncateFeedbackString(progressData.stdout)
|
|
5277
|
+
].slice(-100);
|
|
5226
5278
|
this.emit("stdout", progressData.stdout);
|
|
5227
5279
|
}
|
|
5228
5280
|
if (progressData.stderr) {
|
|
5229
5281
|
this.markStarted();
|
|
5230
|
-
this.metadata.stderr = [
|
|
5282
|
+
this.metadata.stderr = [
|
|
5283
|
+
...this.metadata.stderr,
|
|
5284
|
+
truncateFeedbackString(progressData.stderr)
|
|
5285
|
+
].slice(-100);
|
|
5231
5286
|
this.emit("stderr", progressData.stderr);
|
|
5232
5287
|
}
|
|
5233
5288
|
}
|
|
@@ -5249,12 +5304,18 @@ var JobImplementation = class {
|
|
|
5249
5304
|
});
|
|
5250
5305
|
this.client.on(`job.${id}.stdout`, (line) => {
|
|
5251
5306
|
this.markStarted();
|
|
5252
|
-
this.metadata.stdout = [
|
|
5307
|
+
this.metadata.stdout = [
|
|
5308
|
+
...this.metadata.stdout,
|
|
5309
|
+
truncateFeedbackString(String(line))
|
|
5310
|
+
].slice(-100);
|
|
5253
5311
|
this.emit("stdout", line);
|
|
5254
5312
|
});
|
|
5255
5313
|
this.client.on(`job.${id}.stderr`, (line) => {
|
|
5256
5314
|
this.markStarted();
|
|
5257
|
-
this.metadata.stderr = [
|
|
5315
|
+
this.metadata.stderr = [
|
|
5316
|
+
...this.metadata.stderr,
|
|
5317
|
+
truncateFeedbackString(String(line))
|
|
5318
|
+
].slice(-100);
|
|
5258
5319
|
this.emit("stderr", line);
|
|
5259
5320
|
});
|
|
5260
5321
|
this.client.on(`job.${id}.result`, (result) => {
|
|
@@ -5286,7 +5347,11 @@ var JobImplementation = class {
|
|
|
5286
5347
|
this.client.on("job.failed", (data) => {
|
|
5287
5348
|
const jobData = data;
|
|
5288
5349
|
if (jobData.jobId === id) {
|
|
5289
|
-
this.finalize(
|
|
5350
|
+
this.finalize(
|
|
5351
|
+
"failed",
|
|
5352
|
+
void 0,
|
|
5353
|
+
jobData.error || new Error("Job failed")
|
|
5354
|
+
);
|
|
5290
5355
|
this.emit("status", this.status);
|
|
5291
5356
|
}
|
|
5292
5357
|
});
|
|
@@ -5299,7 +5364,12 @@ var JobImplementation = class {
|
|
|
5299
5364
|
input: sanitizeFeedbackValue(d.input),
|
|
5300
5365
|
startedAt: d.timestamp || Date.now()
|
|
5301
5366
|
});
|
|
5302
|
-
this.emit("toolCallStart", {
|
|
5367
|
+
this.emit("toolCallStart", {
|
|
5368
|
+
callId: d.callId,
|
|
5369
|
+
toolName: d.toolName,
|
|
5370
|
+
input: d.input,
|
|
5371
|
+
timestamp: d.timestamp
|
|
5372
|
+
});
|
|
5303
5373
|
}
|
|
5304
5374
|
});
|
|
5305
5375
|
this.client.on("tool.call.end", (data) => {
|
|
@@ -5314,7 +5384,25 @@ var JobImplementation = class {
|
|
|
5314
5384
|
completedAt,
|
|
5315
5385
|
durationMs: typeof d.durationMs === "number" ? d.durationMs : void 0
|
|
5316
5386
|
});
|
|
5317
|
-
this.emit("toolCallEnd", {
|
|
5387
|
+
this.emit("toolCallEnd", {
|
|
5388
|
+
callId: d.callId,
|
|
5389
|
+
toolName: d.toolName,
|
|
5390
|
+
result: d.result,
|
|
5391
|
+
error: d.error,
|
|
5392
|
+
durationMs: d.durationMs,
|
|
5393
|
+
timestamp: d.timestamp
|
|
5394
|
+
});
|
|
5395
|
+
}
|
|
5396
|
+
});
|
|
5397
|
+
this.client.on("job.agent_message", (data) => {
|
|
5398
|
+
const d = data;
|
|
5399
|
+
if (d.jobId === id) {
|
|
5400
|
+
this.emit("agentMessage", {
|
|
5401
|
+
messageId: d.messageId,
|
|
5402
|
+
reply: typeof d.reply === "string" ? d.reply : "",
|
|
5403
|
+
show: d.show,
|
|
5404
|
+
timestamp: d.timestamp || Date.now()
|
|
5405
|
+
});
|
|
5318
5406
|
}
|
|
5319
5407
|
});
|
|
5320
5408
|
}
|
|
@@ -5384,7 +5472,9 @@ var JobImplementation = class {
|
|
|
5384
5472
|
}
|
|
5385
5473
|
upsertToolCall(next) {
|
|
5386
5474
|
const callId = next.callId || `tool-call-${Date.now()}`;
|
|
5387
|
-
const existingIndex = this.metadata.toolCalls.findIndex(
|
|
5475
|
+
const existingIndex = this.metadata.toolCalls.findIndex(
|
|
5476
|
+
(entry) => entry.callId === callId
|
|
5477
|
+
);
|
|
5388
5478
|
const existing = existingIndex >= 0 ? this.metadata.toolCalls[existingIndex] : void 0;
|
|
5389
5479
|
const merged = {
|
|
5390
5480
|
...existing,
|
|
@@ -13349,7 +13439,8 @@ function uniqueStrings(values, maxCount) {
|
|
|
13349
13439
|
}
|
|
13350
13440
|
function formatScalar(value) {
|
|
13351
13441
|
if (typeof value === "string") return JSON.stringify(value);
|
|
13352
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
13442
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
13443
|
+
return String(value);
|
|
13353
13444
|
if (value === null) return "null";
|
|
13354
13445
|
return "unknown";
|
|
13355
13446
|
}
|
|
@@ -13357,7 +13448,9 @@ function describeHeapEntry(entry, previewFieldLimit = 3) {
|
|
|
13357
13448
|
const headline = entry.label || entry.id || entry.path || "Unknown";
|
|
13358
13449
|
const pathLabel = entry.path && entry.path !== headline ? ` <${entry.path}>` : "";
|
|
13359
13450
|
const classLabel = entry.className || "unknown";
|
|
13360
|
-
const preview = asArray(entry.fields).filter(
|
|
13451
|
+
const preview = asArray(entry.fields).filter(
|
|
13452
|
+
(field) => field?.name && field.name !== "_realId" && field.name !== "real_id"
|
|
13453
|
+
).slice(0, previewFieldLimit).map((field) => `${field.name}=${formatScalar(field.value)}`).join(", ");
|
|
13361
13454
|
return preview ? `${headline}${pathLabel} [${classLabel}] ${preview}` : `${headline}${pathLabel} [${classLabel}]`;
|
|
13362
13455
|
}
|
|
13363
13456
|
function hashString(value) {
|
|
@@ -13373,7 +13466,9 @@ function hasSubstantiveAwaitAfterPrompt(code, marker) {
|
|
|
13373
13466
|
const startIndex = code.indexOf(marker);
|
|
13374
13467
|
if (startIndex === -1) return true;
|
|
13375
13468
|
const segment = code.slice(startIndex + marker.length);
|
|
13376
|
-
const callMatches = segment.matchAll(
|
|
13469
|
+
const callMatches = segment.matchAll(
|
|
13470
|
+
/await\s+([A-Za-z0-9_$.]+)\.([A-Za-z0-9_]+)\s*\(/g
|
|
13471
|
+
);
|
|
13377
13472
|
for (const match of callMatches) {
|
|
13378
13473
|
const receiver = match[1] || "";
|
|
13379
13474
|
const method = match[2] || "";
|
|
@@ -13405,9 +13500,16 @@ function reviewGeneratedJobCode(code) {
|
|
|
13405
13500
|
/approved\./i
|
|
13406
13501
|
];
|
|
13407
13502
|
if (normalized.includes("await loop.confirm(")) {
|
|
13408
|
-
const postConfirm = normalized.slice(
|
|
13409
|
-
|
|
13410
|
-
|
|
13503
|
+
const postConfirm = normalized.slice(
|
|
13504
|
+
normalized.indexOf("await loop.confirm(")
|
|
13505
|
+
);
|
|
13506
|
+
const hasPlaceholder = placeholderPatterns.some(
|
|
13507
|
+
(pattern) => pattern.test(postConfirm)
|
|
13508
|
+
);
|
|
13509
|
+
const hasSubstantiveAwait = hasSubstantiveAwaitAfterPrompt(
|
|
13510
|
+
normalized,
|
|
13511
|
+
"await loop.confirm("
|
|
13512
|
+
);
|
|
13411
13513
|
if (!hasSubstantiveAwait || hasPlaceholder) {
|
|
13412
13514
|
issues.push({
|
|
13413
13515
|
code: "placeholder_after_confirm",
|
|
@@ -13417,9 +13519,16 @@ function reviewGeneratedJobCode(code) {
|
|
|
13417
13519
|
}
|
|
13418
13520
|
}
|
|
13419
13521
|
if (normalized.includes("await loop.ask_user(")) {
|
|
13420
|
-
const postPrompt = normalized.slice(
|
|
13421
|
-
|
|
13422
|
-
|
|
13522
|
+
const postPrompt = normalized.slice(
|
|
13523
|
+
normalized.indexOf("await loop.ask_user(")
|
|
13524
|
+
);
|
|
13525
|
+
const hasPlaceholder = placeholderPatterns.some(
|
|
13526
|
+
(pattern) => pattern.test(postPrompt)
|
|
13527
|
+
);
|
|
13528
|
+
const hasSubstantiveAwait = hasSubstantiveAwaitAfterPrompt(
|
|
13529
|
+
normalized,
|
|
13530
|
+
"await loop.ask_user("
|
|
13531
|
+
);
|
|
13423
13532
|
if (hasPlaceholder && !hasSubstantiveAwait) {
|
|
13424
13533
|
issues.push({
|
|
13425
13534
|
code: "placeholder_after_ask_user",
|
|
@@ -13500,7 +13609,9 @@ function getLatestClosure(liveDoc) {
|
|
|
13500
13609
|
if (!record) continue;
|
|
13501
13610
|
closures.push({ ...record, closureId });
|
|
13502
13611
|
}
|
|
13503
|
-
closures.sort(
|
|
13612
|
+
closures.sort(
|
|
13613
|
+
(left, right) => (Number(right.createdAt) || 0) - (Number(left.createdAt) || 0)
|
|
13614
|
+
);
|
|
13504
13615
|
return closures[0] || null;
|
|
13505
13616
|
}
|
|
13506
13617
|
function getWorkflowBoundary(liveDoc, options) {
|
|
@@ -13538,7 +13649,9 @@ function getJobRecords(liveDoc) {
|
|
|
13538
13649
|
if (!record) continue;
|
|
13539
13650
|
jobs.push({ ...record, jobId });
|
|
13540
13651
|
}
|
|
13541
|
-
jobs.sort(
|
|
13652
|
+
jobs.sort(
|
|
13653
|
+
(left, right) => getJobTimestamp(right) - getJobTimestamp(left)
|
|
13654
|
+
);
|
|
13542
13655
|
return jobs;
|
|
13543
13656
|
}
|
|
13544
13657
|
function getPromptRecordsFromJobs(liveDoc) {
|
|
@@ -13546,7 +13659,9 @@ function getPromptRecordsFromJobs(liveDoc) {
|
|
|
13546
13659
|
}
|
|
13547
13660
|
function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
13548
13661
|
const boundary = getWorkflowBoundary(liveDoc, options);
|
|
13549
|
-
const jobs = getJobRecords(liveDoc).filter(
|
|
13662
|
+
const jobs = getJobRecords(liveDoc).filter(
|
|
13663
|
+
(job) => getJobTimestamp(job) >= boundary.timestamp
|
|
13664
|
+
).slice(0, 6).reverse();
|
|
13550
13665
|
const actionSummaryLines = [];
|
|
13551
13666
|
const variableNames = [];
|
|
13552
13667
|
const listNames = [];
|
|
@@ -13598,7 +13713,9 @@ function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
|
13598
13713
|
return updatedAt >= boundary.timestamp;
|
|
13599
13714
|
}
|
|
13600
13715
|
return status !== "completed" && status !== "canceled" ? true : updatedAt >= boundary.timestamp;
|
|
13601
|
-
}).sort(
|
|
13716
|
+
}).sort(
|
|
13717
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13718
|
+
);
|
|
13602
13719
|
for (const task of tasks.slice(0, 4)) {
|
|
13603
13720
|
if (typeof task.taskId === "string") {
|
|
13604
13721
|
activeTaskIds.push(task.taskId);
|
|
@@ -13610,7 +13727,9 @@ function projectWorkflowFocus(liveDoc, pendingPrompts = [], options) {
|
|
|
13610
13727
|
return updatedAt >= boundary.timestamp;
|
|
13611
13728
|
}
|
|
13612
13729
|
return decision.status === "open" || updatedAt >= boundary.timestamp;
|
|
13613
|
-
}).sort(
|
|
13730
|
+
}).sort(
|
|
13731
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13732
|
+
);
|
|
13614
13733
|
for (const decision of decisions.slice(0, 3)) {
|
|
13615
13734
|
if (typeof decision.decisionId === "string" && decision.status === "open") {
|
|
13616
13735
|
openDecisionIds.push(decision.decisionId);
|
|
@@ -13689,11 +13808,15 @@ function projectWorkflowSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13689
13808
|
const lines = [];
|
|
13690
13809
|
lines.push("Workflow Boundary:");
|
|
13691
13810
|
if (focus.boundaryReason === "request_start") {
|
|
13692
|
-
lines.push(
|
|
13811
|
+
lines.push(
|
|
13812
|
+
"- Start from work recorded after the current user request began."
|
|
13813
|
+
);
|
|
13693
13814
|
} else if (focus.boundaryReason === "last_closed_loop" && focus.latestClosureId) {
|
|
13694
13815
|
lines.push(`- Start from work recorded after ${focus.latestClosureId}.`);
|
|
13695
13816
|
} else {
|
|
13696
|
-
lines.push(
|
|
13817
|
+
lines.push(
|
|
13818
|
+
"- No prior closed loop recorded; use the latest user request as the boundary."
|
|
13819
|
+
);
|
|
13697
13820
|
}
|
|
13698
13821
|
lines.push("", "Recent Actions:");
|
|
13699
13822
|
if (focus.recentActionSummary.length === 0) {
|
|
@@ -13757,12 +13880,17 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13757
13880
|
return updatedAt >= boundary.timestamp;
|
|
13758
13881
|
}
|
|
13759
13882
|
return status !== "completed" && status !== "canceled" ? true : updatedAt >= boundary.timestamp;
|
|
13760
|
-
}).sort(
|
|
13883
|
+
}).sort(
|
|
13884
|
+
(left, right) => (Number(right.updatedAt) || 0) - (Number(left.updatedAt) || 0)
|
|
13885
|
+
);
|
|
13761
13886
|
const activeTasks = tasks.filter((task) => {
|
|
13762
13887
|
const status = typeof task.status === "string" ? task.status : "pending";
|
|
13763
13888
|
return status !== "completed" && status !== "canceled";
|
|
13764
13889
|
});
|
|
13765
|
-
const visibleTasks = (activeTasks.length > 0 ? activeTasks : tasks).slice(
|
|
13890
|
+
const visibleTasks = (activeTasks.length > 0 ? activeTasks : tasks).slice(
|
|
13891
|
+
0,
|
|
13892
|
+
5
|
|
13893
|
+
);
|
|
13766
13894
|
const hiddenTaskCount = Math.max(0, activeTasks.length - visibleTasks.length);
|
|
13767
13895
|
lines.push("Tasks:");
|
|
13768
13896
|
if (visibleTasks.length === 0) {
|
|
@@ -13786,8 +13914,12 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13786
13914
|
return updatedAt >= boundary.timestamp;
|
|
13787
13915
|
}
|
|
13788
13916
|
return decision.status === "open" || updatedAt >= boundary.timestamp;
|
|
13789
|
-
}).sort(
|
|
13790
|
-
|
|
13917
|
+
}).sort(
|
|
13918
|
+
(left, right) => (Number(right.updatedAt) || Number(right.createdAt) || 0) - (Number(left.updatedAt) || Number(left.createdAt) || 0)
|
|
13919
|
+
);
|
|
13920
|
+
const openDecisions = decisions.filter(
|
|
13921
|
+
(decision) => decision.status === "open"
|
|
13922
|
+
);
|
|
13791
13923
|
const visibleDecisions = (openDecisions.length > 0 ? openDecisions : decisions.slice(0, 1)).slice(0, 3);
|
|
13792
13924
|
lines.push("", "Recent Decisions:");
|
|
13793
13925
|
if (visibleDecisions.length === 0) {
|
|
@@ -13806,7 +13938,9 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13806
13938
|
const candidateLabel = typeof record.label === "string" && record.label.trim() ? record.label.trim() : candidateId;
|
|
13807
13939
|
return candidateLabel === candidateId ? candidateId : `${candidateLabel} (${candidateId})`;
|
|
13808
13940
|
}).filter((value) => Boolean(value)).join(", ");
|
|
13809
|
-
lines.push(
|
|
13941
|
+
lines.push(
|
|
13942
|
+
`- [open] ${title} (${decisionId})${candidatePreview ? ` \u2014 candidates: ${candidatePreview}` : ""}`
|
|
13943
|
+
);
|
|
13810
13944
|
} else {
|
|
13811
13945
|
const selected = asRecord2(decision.selected);
|
|
13812
13946
|
const label = typeof selected?.label === "string" ? selected.label : typeof selected?.id === "string" ? selected.id : "unknown";
|
|
@@ -13821,13 +13955,17 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
|
|
|
13821
13955
|
title: prompt.title,
|
|
13822
13956
|
message: prompt.message
|
|
13823
13957
|
})),
|
|
13824
|
-
...Object.values(asRecord2(asRecord2(liveDoc?.jobs)?.byId) || {}).flatMap((job) => Object.values(asRecord2(asRecord2(job)?.prompts) || {})).map((prompt) => asRecord2(prompt)).filter(
|
|
13958
|
+
...Object.values(asRecord2(asRecord2(liveDoc?.jobs)?.byId) || {}).flatMap((job) => Object.values(asRecord2(asRecord2(job)?.prompts) || {})).map((prompt) => asRecord2(prompt)).filter(
|
|
13959
|
+
(prompt) => Boolean(prompt && prompt.status === "open")
|
|
13960
|
+
)
|
|
13825
13961
|
];
|
|
13826
13962
|
const visiblePrompts = boundary.reason === "request_start" ? openPrompts.filter((prompt) => {
|
|
13827
13963
|
const promptRecord = asRecord2(prompt);
|
|
13828
13964
|
const openedAt = Number(promptRecord?.openedAt) || 0;
|
|
13829
13965
|
const promptId = typeof promptRecord?.id === "string" ? promptRecord.id : typeof prompt.id === "string" ? prompt.id : null;
|
|
13830
|
-
return openedAt >= boundary.timestamp || (promptId ? pendingPrompts.some(
|
|
13966
|
+
return openedAt >= boundary.timestamp || (promptId ? pendingPrompts.some(
|
|
13967
|
+
(pendingPrompt) => pendingPrompt.id === promptId
|
|
13968
|
+
) : false);
|
|
13831
13969
|
}) : openPrompts;
|
|
13832
13970
|
lines.push("", "Open Prompts:");
|
|
13833
13971
|
if (visiblePrompts.length === 0) {
|
|
@@ -13858,9 +13996,15 @@ function projectHeapSummary(heap, options) {
|
|
|
13858
13996
|
const entriesByPath = asRecord2(heapRecord.entriesByPath) || {};
|
|
13859
13997
|
const listsByName = asRecord2(heapRecord.listsByName) || {};
|
|
13860
13998
|
const variablesByName = asRecord2(heapRecord.variablesByName) || {};
|
|
13861
|
-
const focusedVariableNames = new Set(
|
|
13862
|
-
|
|
13863
|
-
|
|
13999
|
+
const focusedVariableNames = new Set(
|
|
14000
|
+
uniqueStrings(options?.focus?.variableNames || [])
|
|
14001
|
+
);
|
|
14002
|
+
const focusedListNames = new Set(
|
|
14003
|
+
uniqueStrings(options?.focus?.listNames || [])
|
|
14004
|
+
);
|
|
14005
|
+
const focusedEntryPaths = new Set(
|
|
14006
|
+
uniqueStrings(options?.focus?.entryPaths || [])
|
|
14007
|
+
);
|
|
13864
14008
|
const hasFocus = focusedVariableNames.size > 0 || focusedListNames.size > 0 || focusedEntryPaths.size > 0;
|
|
13865
14009
|
const suppressRecentFallback = Boolean(options?.focus) && !hasFocus;
|
|
13866
14010
|
const maxVariables = options?.maxVariables ?? (hasFocus ? 4 : 6);
|
|
@@ -13872,20 +14016,26 @@ function projectHeapSummary(heap, options) {
|
|
|
13872
14016
|
return rightFocused - leftFocused || (right.updatedAt || 0) - (left.updatedAt || 0);
|
|
13873
14017
|
}).filter((variable, index) => {
|
|
13874
14018
|
if (index < maxVariables) return true;
|
|
13875
|
-
return Boolean(
|
|
14019
|
+
return Boolean(
|
|
14020
|
+
variable.name && focusedVariableNames.has(variable.name)
|
|
14021
|
+
);
|
|
13876
14022
|
}).slice(0, maxVariables);
|
|
13877
14023
|
const referencedPaths = /* @__PURE__ */ new Set();
|
|
13878
14024
|
for (const variable of variables) {
|
|
13879
14025
|
if (variable.entryPath) referencedPaths.add(variable.entryPath);
|
|
13880
14026
|
if (variable.listName) {
|
|
13881
|
-
const list = asRecord2(
|
|
14027
|
+
const list = asRecord2(
|
|
14028
|
+
listsByName[variable.listName]
|
|
14029
|
+
);
|
|
13882
14030
|
for (const path2 of list?.paths || []) referencedPaths.add(path2);
|
|
13883
14031
|
}
|
|
13884
14032
|
}
|
|
13885
14033
|
for (const path2 of focusedEntryPaths) {
|
|
13886
14034
|
referencedPaths.add(path2);
|
|
13887
14035
|
}
|
|
13888
|
-
const visibleLists = Object.values(listsByName).map((value) => asRecord2(value)).filter((value) => Boolean(value)).filter(
|
|
14036
|
+
const visibleLists = Object.values(listsByName).map((value) => asRecord2(value)).filter((value) => Boolean(value)).filter(
|
|
14037
|
+
(list) => variables.some((variable) => variable.listName === list.name) || Boolean(list.name && focusedListNames.has(list.name))
|
|
14038
|
+
).sort((left, right) => (right.updatedAt || 0) - (left.updatedAt || 0)).slice(0, maxLists);
|
|
13889
14039
|
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);
|
|
13890
14040
|
const lines = [];
|
|
13891
14041
|
lines.push("Variables:");
|
|
@@ -13894,16 +14044,24 @@ function projectHeapSummary(heap, options) {
|
|
|
13894
14044
|
} else {
|
|
13895
14045
|
for (const variable of variables) {
|
|
13896
14046
|
if (variable.kind === "scalar") {
|
|
13897
|
-
lines.push(
|
|
14047
|
+
lines.push(
|
|
14048
|
+
`- ${variable.name}: scalar = ${formatScalar(variable.value)}`
|
|
14049
|
+
);
|
|
13898
14050
|
continue;
|
|
13899
14051
|
}
|
|
13900
14052
|
if (variable.kind === "entry") {
|
|
13901
|
-
const entry = variable.entryPath ? asRecord2(
|
|
13902
|
-
|
|
14053
|
+
const entry = variable.entryPath ? asRecord2(
|
|
14054
|
+
entriesByPath[variable.entryPath]
|
|
14055
|
+
) : null;
|
|
14056
|
+
lines.push(
|
|
14057
|
+
`- ${variable.name}: entry<${variable.className || entry?.className || "unknown"}> -> ${entry ? describeHeapEntry(entry) : variable.entryPath || "missing"}`
|
|
14058
|
+
);
|
|
13903
14059
|
continue;
|
|
13904
14060
|
}
|
|
13905
14061
|
const list = variable.listName ? asRecord2(listsByName[variable.listName]) : null;
|
|
13906
|
-
lines.push(
|
|
14062
|
+
lines.push(
|
|
14063
|
+
`- ${variable.name}: list<${variable.className || list?.className || "unknown"}> -> ${(list?.paths || []).length} item(s)`
|
|
14064
|
+
);
|
|
13907
14065
|
}
|
|
13908
14066
|
}
|
|
13909
14067
|
lines.push("", "Named Lists:");
|
|
@@ -13911,7 +14069,9 @@ function projectHeapSummary(heap, options) {
|
|
|
13911
14069
|
lines.push("- none");
|
|
13912
14070
|
} else {
|
|
13913
14071
|
for (const list of visibleLists) {
|
|
13914
|
-
lines.push(
|
|
14072
|
+
lines.push(
|
|
14073
|
+
`- ${list.name}: ${list.className || "unknown"}[${(list.paths || []).length}]`
|
|
14074
|
+
);
|
|
13915
14075
|
}
|
|
13916
14076
|
}
|
|
13917
14077
|
lines.push("", "Active Entries:");
|
|
@@ -13925,11 +14085,19 @@ function projectHeapSummary(heap, options) {
|
|
|
13925
14085
|
return lines.join("\n");
|
|
13926
14086
|
}
|
|
13927
14087
|
function createHarnessVerifierSnapshot(input) {
|
|
13928
|
-
const workflowFocus = projectWorkflowFocus(
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
14088
|
+
const workflowFocus = projectWorkflowFocus(
|
|
14089
|
+
input.liveDoc,
|
|
14090
|
+
[],
|
|
14091
|
+
input.projectionOptions
|
|
14092
|
+
);
|
|
14093
|
+
const heapDigest = hashString(
|
|
14094
|
+
projectHeapSummary(asRecord2(input.liveDoc?.heap), {
|
|
14095
|
+
focus: workflowFocus
|
|
14096
|
+
})
|
|
14097
|
+
) || "00000000";
|
|
14098
|
+
const loopDigest = hashString(
|
|
14099
|
+
projectWorkflowSummary(input.liveDoc, [], input.projectionOptions)
|
|
14100
|
+
) || "00000000";
|
|
13933
14101
|
return {
|
|
13934
14102
|
codeDigest: hashString(input.finalCode?.trim()),
|
|
13935
14103
|
resultDigest: hashString(input.resultPreview?.trim()),
|
|
@@ -14059,8 +14227,12 @@ function buildGranularAgentToolBlock(tools) {
|
|
|
14059
14227
|
return "No live effects are available in this session yet.";
|
|
14060
14228
|
}
|
|
14061
14229
|
const globalTools = normalizedTools.filter((tool) => !tool.className);
|
|
14062
|
-
const staticTools = normalizedTools.filter(
|
|
14063
|
-
|
|
14230
|
+
const staticTools = normalizedTools.filter(
|
|
14231
|
+
(tool) => Boolean(tool.className && tool.static)
|
|
14232
|
+
);
|
|
14233
|
+
const instanceTools = normalizedTools.filter(
|
|
14234
|
+
(tool) => Boolean(tool.className && !tool.static)
|
|
14235
|
+
);
|
|
14064
14236
|
const lines = [
|
|
14065
14237
|
"Treat this block as the planning map. Use DOMAIN TYPES below for exact signatures."
|
|
14066
14238
|
];
|
|
@@ -14275,7 +14447,10 @@ ${loopBlock}
|
|
|
14275
14447
|
- Avoid \`as any\` and other broad casts when the DOMAIN TYPES block already tells you the correct class or list type.
|
|
14276
14448
|
- Prefer manipulating heap-backed instances and typed lists instead of returning raw JSON blobs or object IDs unless the user explicitly asks for them.
|
|
14277
14449
|
- 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.
|
|
14450
|
+
- You may call \`agent_message(...)\` multiple times in one job to post several assistant messages while the job is still running.
|
|
14278
14451
|
- Prefer \`agent_message({ reply, show })\` when you want to leave a user-facing answer and optionally show heap-backed records in the UI.
|
|
14452
|
+
- \`agent_message(...)\` also accepts \`content\`, \`message\`, or \`text\` instead of \`reply\`.
|
|
14453
|
+
- \`agent_message({ show })\` may receive explicit refs or sandbox instances and arrays of sandbox instances. The runtime will convert those into UI references.
|
|
14279
14454
|
- When it helps the UI show specific heap-backed results, you may instead return:
|
|
14280
14455
|
\`{ reply: string, show: { entryPaths?: string[], listNames?: string[], variableNames?: string[] } }\`
|
|
14281
14456
|
- 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.
|