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