@granular-software/sdk 0.4.24 → 0.4.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-evals.d.mts +1 -1
- package/dist/agent-evals.d.ts +1 -1
- package/dist/agent-evals.js +161 -38
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +161 -38
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.d.mts +1 -1
- package/dist/agent-harness.d.ts +1 -1
- package/dist/agent-harness.js +22 -11
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +22 -11
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +97 -8
- package/dist/{client-CQFKsCTd.d.mts → client-Zoo8YITZ.d.mts} +39 -1
- package/dist/{client-CQFKsCTd.d.ts → client-Zoo8YITZ.d.ts} +39 -1
- package/dist/index.d.mts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +462 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +462 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4567,6 +4567,7 @@ var Session = class {
|
|
|
4567
4567
|
client;
|
|
4568
4568
|
clientId;
|
|
4569
4569
|
jobsMap = /* @__PURE__ */ new Map();
|
|
4570
|
+
pendingAgentMessagesByJobId = /* @__PURE__ */ new Map();
|
|
4570
4571
|
eventListeners = /* @__PURE__ */ new Map();
|
|
4571
4572
|
toolHandlers = /* @__PURE__ */ new Map();
|
|
4572
4573
|
/** Tracks which tools are instance methods (className set, not static) */
|
|
@@ -4609,6 +4610,22 @@ var Session = class {
|
|
|
4609
4610
|
}
|
|
4610
4611
|
};
|
|
4611
4612
|
}
|
|
4613
|
+
stringifyConversationValue(value) {
|
|
4614
|
+
if (typeof value === "string") {
|
|
4615
|
+
return value;
|
|
4616
|
+
}
|
|
4617
|
+
if (typeof value === "boolean") {
|
|
4618
|
+
return value ? "Confirmed" : "Canceled";
|
|
4619
|
+
}
|
|
4620
|
+
if (value === void 0) {
|
|
4621
|
+
return "";
|
|
4622
|
+
}
|
|
4623
|
+
try {
|
|
4624
|
+
return JSON.stringify(value, null, 2);
|
|
4625
|
+
} catch {
|
|
4626
|
+
return String(value);
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4612
4629
|
// --- Public API ---
|
|
4613
4630
|
get document() {
|
|
4614
4631
|
return this.client.doc;
|
|
@@ -4724,6 +4741,15 @@ var Session = class {
|
|
|
4724
4741
|
createdAt: Date.now()
|
|
4725
4742
|
});
|
|
4726
4743
|
this.jobsMap.set(result.jobId, job);
|
|
4744
|
+
const pendingAgentMessages = this.pendingAgentMessagesByJobId.get(
|
|
4745
|
+
result.jobId
|
|
4746
|
+
);
|
|
4747
|
+
if (pendingAgentMessages && pendingAgentMessages.length > 0) {
|
|
4748
|
+
this.pendingAgentMessagesByJobId.delete(result.jobId);
|
|
4749
|
+
for (const message of pendingAgentMessages) {
|
|
4750
|
+
job.replayAgentMessage(message);
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4727
4753
|
return job;
|
|
4728
4754
|
}
|
|
4729
4755
|
/**
|
|
@@ -4750,6 +4776,20 @@ var Session = class {
|
|
|
4750
4776
|
answer: resolvedAnswer,
|
|
4751
4777
|
value: resolvedAnswer
|
|
4752
4778
|
});
|
|
4779
|
+
try {
|
|
4780
|
+
const content = this.stringifyConversationValue(resolvedAnswer);
|
|
4781
|
+
if (content.trim()) {
|
|
4782
|
+
await this.appendConversationMessage({
|
|
4783
|
+
role: "user",
|
|
4784
|
+
content,
|
|
4785
|
+
promptId
|
|
4786
|
+
});
|
|
4787
|
+
}
|
|
4788
|
+
} catch {
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
async appendConversationMessage(input) {
|
|
4792
|
+
return this.client.call("conversation.append", input);
|
|
4753
4793
|
}
|
|
4754
4794
|
/**
|
|
4755
4795
|
* Get the current list of available effects.
|
|
@@ -5125,6 +5165,22 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
5125
5165
|
this.client.on("job.status", (data) => {
|
|
5126
5166
|
this.emit("job:status", data);
|
|
5127
5167
|
});
|
|
5168
|
+
this.client.on("job.agent_message", (data) => {
|
|
5169
|
+
const normalized = normalizeJobAgentMessageEnvelope(data);
|
|
5170
|
+
if (!normalized) return;
|
|
5171
|
+
if (this.jobsMap.has(normalized.jobId)) return;
|
|
5172
|
+
const pending = this.pendingAgentMessagesByJobId.get(normalized.jobId) || [];
|
|
5173
|
+
if (normalized.message.messageId && pending.some(
|
|
5174
|
+
(message) => message.messageId === normalized.message.messageId
|
|
5175
|
+
)) {
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
5178
|
+
pending.push(normalized.message);
|
|
5179
|
+
this.pendingAgentMessagesByJobId.set(
|
|
5180
|
+
normalized.jobId,
|
|
5181
|
+
pending.slice(-25)
|
|
5182
|
+
);
|
|
5183
|
+
});
|
|
5128
5184
|
this.client.on("exec.completed", (data) => {
|
|
5129
5185
|
this.emit("exec:completed", data);
|
|
5130
5186
|
});
|
|
@@ -5249,6 +5305,22 @@ function sanitizeFeedbackValue(value, depth = 0, seen = /* @__PURE__ */ new Weak
|
|
|
5249
5305
|
}
|
|
5250
5306
|
return truncateFeedbackString(String(value));
|
|
5251
5307
|
}
|
|
5308
|
+
function normalizeJobAgentMessageEnvelope(data) {
|
|
5309
|
+
const d = data;
|
|
5310
|
+
if (typeof d?.jobId !== "string" || !d.jobId) {
|
|
5311
|
+
return null;
|
|
5312
|
+
}
|
|
5313
|
+
return {
|
|
5314
|
+
jobId: d.jobId,
|
|
5315
|
+
message: {
|
|
5316
|
+
messageId: d.messageId,
|
|
5317
|
+
kind: d.kind === "artifacts" ? "artifacts" : "text",
|
|
5318
|
+
reply: typeof d.reply === "string" ? d.reply : "",
|
|
5319
|
+
show: d.show,
|
|
5320
|
+
timestamp: d.timestamp || Date.now()
|
|
5321
|
+
}
|
|
5322
|
+
};
|
|
5323
|
+
}
|
|
5252
5324
|
var JobImplementation = class {
|
|
5253
5325
|
id;
|
|
5254
5326
|
client;
|
|
@@ -5257,6 +5329,8 @@ var JobImplementation = class {
|
|
|
5257
5329
|
_resolveResult;
|
|
5258
5330
|
_rejectResult;
|
|
5259
5331
|
eventListeners = /* @__PURE__ */ new Map();
|
|
5332
|
+
bufferedAgentMessages = [];
|
|
5333
|
+
bufferedAgentMessageIds = /* @__PURE__ */ new Set();
|
|
5260
5334
|
metadata;
|
|
5261
5335
|
constructor(id, client, initialState) {
|
|
5262
5336
|
this.id = id;
|
|
@@ -5415,14 +5489,9 @@ var JobImplementation = class {
|
|
|
5415
5489
|
}
|
|
5416
5490
|
});
|
|
5417
5491
|
this.client.on("job.agent_message", (data) => {
|
|
5418
|
-
const
|
|
5419
|
-
if (
|
|
5420
|
-
this.
|
|
5421
|
-
messageId: d.messageId,
|
|
5422
|
-
reply: typeof d.reply === "string" ? d.reply : "",
|
|
5423
|
-
show: d.show,
|
|
5424
|
-
timestamp: d.timestamp || Date.now()
|
|
5425
|
-
});
|
|
5492
|
+
const normalized = normalizeJobAgentMessageEnvelope(data);
|
|
5493
|
+
if (normalized?.jobId === id) {
|
|
5494
|
+
this.captureAgentMessage(normalized.message);
|
|
5426
5495
|
}
|
|
5427
5496
|
});
|
|
5428
5497
|
}
|
|
@@ -5449,6 +5518,14 @@ var JobImplementation = class {
|
|
|
5449
5518
|
this.eventListeners.set(event, []);
|
|
5450
5519
|
}
|
|
5451
5520
|
this.eventListeners.get(event).push(handler);
|
|
5521
|
+
if (event === "agentMessage" && this.bufferedAgentMessages.length > 0) {
|
|
5522
|
+
for (const message of this.bufferedAgentMessages) {
|
|
5523
|
+
handler(message);
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
replayAgentMessage(message) {
|
|
5528
|
+
this.captureAgentMessage(message);
|
|
5452
5529
|
}
|
|
5453
5530
|
buildFeedbackMetadata() {
|
|
5454
5531
|
const startedAt = this.metadata.startedAt;
|
|
@@ -5518,6 +5595,18 @@ var JobImplementation = class {
|
|
|
5518
5595
|
handlers.forEach((h) => h(data));
|
|
5519
5596
|
}
|
|
5520
5597
|
}
|
|
5598
|
+
captureAgentMessage(message) {
|
|
5599
|
+
if (message.messageId && this.bufferedAgentMessageIds.has(message.messageId)) {
|
|
5600
|
+
return;
|
|
5601
|
+
}
|
|
5602
|
+
if (message.messageId) {
|
|
5603
|
+
this.bufferedAgentMessageIds.add(message.messageId);
|
|
5604
|
+
}
|
|
5605
|
+
this.bufferedAgentMessages = [...this.bufferedAgentMessages, message].slice(
|
|
5606
|
+
-25
|
|
5607
|
+
);
|
|
5608
|
+
this.emit("agentMessage", message);
|
|
5609
|
+
}
|
|
5521
5610
|
};
|
|
5522
5611
|
|
|
5523
5612
|
// src/endpoints.ts
|
|
@@ -13572,14 +13661,22 @@ function reviewGeneratedJobCode(code) {
|
|
|
13572
13661
|
}
|
|
13573
13662
|
}
|
|
13574
13663
|
}
|
|
13575
|
-
const hasConversationalReturn = /return\s+[`'"]/.test(normalized) || /\breply\s*:/.test(normalized) || /\bagent_message\s*\(/.test(normalized);
|
|
13664
|
+
const hasConversationalReturn = /return\s+[`'"]/.test(normalized) || /\breply\s*:/.test(normalized) || /\bagent_message\s*\(/.test(normalized) || /\bagent_text_message\s*\(/.test(normalized);
|
|
13576
13665
|
const returnsObjectLiteral = /return\s+\{[\s\S]*?\}/.test(normalized);
|
|
13666
|
+
const returnsShowPayload = /return\s+\{[\s\S]*?\bshow\s*:/.test(normalized);
|
|
13577
13667
|
const closesLoop = /loop\.close_loop\s*\(/.test(normalized);
|
|
13578
13668
|
if (!hasConversationalReturn && returnsObjectLiteral && !closesLoop) {
|
|
13579
13669
|
issues.push({
|
|
13580
13670
|
code: "missing_user_reply",
|
|
13581
13671
|
severity: "error",
|
|
13582
|
-
message: "User-facing jobs must end with a natural-language answer. Return a short string, an object with a top-level `reply` string, or
|
|
13672
|
+
message: "User-facing jobs must end with a natural-language answer. Return a short string, an object with a top-level `reply` string, or post text with agent_text_message(...). Do not end with bare structured JSON."
|
|
13673
|
+
});
|
|
13674
|
+
}
|
|
13675
|
+
if (returnsShowPayload) {
|
|
13676
|
+
issues.push({
|
|
13677
|
+
code: "return_show_not_for_ui",
|
|
13678
|
+
severity: "error",
|
|
13679
|
+
message: "Do not use the final return value to send UI record refs through `show`. Use agent_heap_objects(...) for heap-backed UI, then return plain text if you still want a final textual answer."
|
|
13583
13680
|
});
|
|
13584
13681
|
}
|
|
13585
13682
|
return issues;
|
|
@@ -14429,7 +14526,7 @@ ${loopBlock}
|
|
|
14429
14526
|
|
|
14430
14527
|
\u2500\u2500\u2500 CODE RULES \u2500\u2500\u2500
|
|
14431
14528
|
- Import from \`./sandbox-tools\`.
|
|
14432
|
-
- If you use \`heap\`, \`loop\`, or \`agent_message\`, import them explicitly from \`./sandbox-tools\`.
|
|
14529
|
+
- If you use \`heap\`, \`loop\`, \`agent_text_message\`, \`agent_heap_objects\`, or legacy \`agent_message\`, import them explicitly from \`./sandbox-tools\`.
|
|
14433
14530
|
- Write top-level executable code with \`await\` at top level.
|
|
14434
14531
|
- The generated job body must be plain runnable JavaScript. The DOMAIN TYPES block is only a reference for shapes and available methods.
|
|
14435
14532
|
- Do not write TypeScript-only syntax in executable code: no type annotations, no interfaces, no enums, no \`as Type\` casts, no \`satisfies\`, and no generic type parameters in code.
|
|
@@ -14471,21 +14568,31 @@ ${loopBlock}
|
|
|
14471
14568
|
- \`loop.close_loop(...)\`: record the current workflow outcome with a short summary before stopping. Do not call it in the same job that opens a new user prompt unless the workflow is explicitly blocked. This does not end the session forever.
|
|
14472
14569
|
- Avoid \`as any\` and other broad casts when the DOMAIN TYPES block already tells you the correct class or list type.
|
|
14473
14570
|
- Prefer manipulating heap-backed instances and typed lists instead of returning raw JSON blobs or object IDs unless the user explicitly asks for them.
|
|
14474
|
-
-
|
|
14475
|
-
-
|
|
14476
|
-
-
|
|
14477
|
-
- \`
|
|
14478
|
-
- \`
|
|
14479
|
-
-
|
|
14480
|
-
|
|
14481
|
-
-
|
|
14571
|
+
- Every job that intends to answer the user must emit at least one explicit UI message with \`agent_text_message(...)\` and/or \`agent_heap_objects(...)\`.
|
|
14572
|
+
- Use \`agent_text_message("...")\` for all user-visible text shown in the UI.
|
|
14573
|
+
- Use \`agent_heap_objects(...)\` only when you want the UI to render heap-backed records or lists.
|
|
14574
|
+
- If you want to show both text and records, call \`agent_text_message(...)\` and \`agent_heap_objects(...)\` separately in whatever order fits the interaction.
|
|
14575
|
+
- \`agent_text_message(...)\` should be used with a plain text string in normal generated code.
|
|
14576
|
+
- \`agent_heap_objects(...)\` should point at heap-backed values: explicit \`entryPaths\` / \`listNames\` / \`variableNames\`, a named list saved with \`saveAs\`, or values read back from \`heap.getVar(...)\`.
|
|
14577
|
+
- If you just fetched records and want to show them in the UI, save or reference them through the heap first, then call \`agent_heap_objects(...)\`. Do not try to hand-build UI payloads in job code.
|
|
14578
|
+
- Do not assume heap changes will be displayed automatically. If records should appear in the UI, you must call \`agent_heap_objects(...)\`.
|
|
14579
|
+
- Never write \`return { reply, show }\` or \`return { show: ... }\` for UI. If you want the UI to render records or lists, call \`agent_heap_objects(...)\` instead.
|
|
14580
|
+
- Do not rely on the final return value for user-visible output. A plain return value is not considered a displayed UI answer.
|
|
14581
|
+
- \`agent_message(...)\` remains available as a legacy compatibility alias, but prefer \`agent_text_message(...)\` and \`agent_heap_objects(...)\` in new code.
|
|
14482
14582
|
- Do not return bare structured JSON, low-level diagnostics, or database-shaped payloads as the final answer unless the user explicitly asks for them.
|
|
14483
14583
|
- Prefer simple executable JavaScript over clever interpolation. Avoid nested template literals or unusually dense inline expressions when a small temporary variable or string concatenation would be clearer and safer.
|
|
14484
14584
|
- Use \`console.log()\` only for intermediate diagnostics, not for the final user-facing answer.`;
|
|
14485
14585
|
}
|
|
14486
14586
|
|
|
14487
14587
|
// src/job-presentation.ts
|
|
14488
|
-
var RESPONSE_KEYS = [
|
|
14588
|
+
var RESPONSE_KEYS = [
|
|
14589
|
+
"reply",
|
|
14590
|
+
"response",
|
|
14591
|
+
"text",
|
|
14592
|
+
"message",
|
|
14593
|
+
"summary",
|
|
14594
|
+
"answer"
|
|
14595
|
+
];
|
|
14489
14596
|
var ENTRY_KEY_CANDIDATES = ["entryPath", "path"];
|
|
14490
14597
|
var ENTRY_ARRAY_KEY_CANDIDATES = ["entryPaths", "paths"];
|
|
14491
14598
|
var LIST_KEY_CANDIDATES = ["listName"];
|
|
@@ -14527,15 +14634,22 @@ function pushStringArray(target, value) {
|
|
|
14527
14634
|
}
|
|
14528
14635
|
}
|
|
14529
14636
|
function collectReferencesFromRecord(record, refs) {
|
|
14530
|
-
for (const key of ENTRY_KEY_CANDIDATES)
|
|
14531
|
-
|
|
14532
|
-
for (const key of
|
|
14533
|
-
|
|
14534
|
-
for (const key of
|
|
14535
|
-
|
|
14637
|
+
for (const key of ENTRY_KEY_CANDIDATES)
|
|
14638
|
+
pushString(refs.entryPaths, record[key]);
|
|
14639
|
+
for (const key of ENTRY_ARRAY_KEY_CANDIDATES)
|
|
14640
|
+
pushStringArray(refs.entryPaths, record[key]);
|
|
14641
|
+
for (const key of LIST_KEY_CANDIDATES)
|
|
14642
|
+
pushString(refs.listNames, record[key]);
|
|
14643
|
+
for (const key of LIST_ARRAY_KEY_CANDIDATES)
|
|
14644
|
+
pushStringArray(refs.listNames, record[key]);
|
|
14645
|
+
for (const key of VARIABLE_KEY_CANDIDATES)
|
|
14646
|
+
pushString(refs.variableNames, record[key]);
|
|
14647
|
+
for (const key of VARIABLE_ARRAY_KEY_CANDIDATES)
|
|
14648
|
+
pushStringArray(refs.variableNames, record[key]);
|
|
14536
14649
|
}
|
|
14537
14650
|
function scanForHeapReferences(value, heap, refs, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
14538
|
-
if (value === null || value === void 0 || depth > 4 || seen.has(value))
|
|
14651
|
+
if (value === null || value === void 0 || depth > 4 || seen.has(value))
|
|
14652
|
+
return;
|
|
14539
14653
|
if (typeof value === "string") {
|
|
14540
14654
|
const trimmed = value.trim();
|
|
14541
14655
|
if (heap.entriesByPath?.[trimmed]) refs.entryPaths.add(trimmed);
|
|
@@ -14631,12 +14745,16 @@ function fallbackResponseText(entries, lists) {
|
|
|
14631
14745
|
}
|
|
14632
14746
|
function getJobRelatedEntries(heap, jobId) {
|
|
14633
14747
|
return sortEntries(
|
|
14634
|
-
Object.values(heap.entriesByPath || {}).filter(
|
|
14748
|
+
Object.values(heap.entriesByPath || {}).filter(
|
|
14749
|
+
(entry) => entry.relatedJobIds?.includes(jobId)
|
|
14750
|
+
)
|
|
14635
14751
|
);
|
|
14636
14752
|
}
|
|
14637
14753
|
function getJobRelatedLists(heap, jobId) {
|
|
14638
14754
|
return sortLists(
|
|
14639
|
-
Object.values(heap.listsByName || {}).filter(
|
|
14755
|
+
Object.values(heap.listsByName || {}).filter(
|
|
14756
|
+
(list) => list.relatedJobIds?.includes(jobId)
|
|
14757
|
+
)
|
|
14640
14758
|
);
|
|
14641
14759
|
}
|
|
14642
14760
|
function entriesFromLists(lists, heap) {
|
|
@@ -14653,15 +14771,18 @@ function resolveJobPresentation({
|
|
|
14653
14771
|
jobId,
|
|
14654
14772
|
result,
|
|
14655
14773
|
stdout = [],
|
|
14656
|
-
sessionHeap
|
|
14774
|
+
sessionHeap,
|
|
14775
|
+
allowExplicitArtifacts = true
|
|
14657
14776
|
}) {
|
|
14658
14777
|
const refs = {
|
|
14659
14778
|
entryPaths: /* @__PURE__ */ new Set(),
|
|
14660
14779
|
listNames: /* @__PURE__ */ new Set(),
|
|
14661
14780
|
variableNames: /* @__PURE__ */ new Set()
|
|
14662
14781
|
};
|
|
14663
|
-
|
|
14664
|
-
|
|
14782
|
+
if (allowExplicitArtifacts) {
|
|
14783
|
+
scanForHeapReferences(result, sessionHeap, refs);
|
|
14784
|
+
resolveVariablesToReferences(refs.variableNames, sessionHeap, refs);
|
|
14785
|
+
}
|
|
14665
14786
|
const referencedLists = sortLists(
|
|
14666
14787
|
[...refs.listNames].map((name) => sessionHeap.listsByName?.[name]).filter((list) => Boolean(list))
|
|
14667
14788
|
);
|
|
@@ -14674,22 +14795,324 @@ function resolveJobPresentation({
|
|
|
14674
14795
|
...jobEntries,
|
|
14675
14796
|
...entriesFromLists(jobLists, sessionHeap)
|
|
14676
14797
|
]);
|
|
14677
|
-
const
|
|
14678
|
-
const
|
|
14798
|
+
const explicitLists = dedupeLists(referencedLists);
|
|
14799
|
+
const explicitEntries = dedupeEntries([
|
|
14679
14800
|
...referencedEntries,
|
|
14680
|
-
...entriesFromLists(referencedLists, sessionHeap)
|
|
14681
|
-
...jobEntries,
|
|
14682
|
-
...entriesFromLists(jobLists, sessionHeap)
|
|
14801
|
+
...entriesFromLists(referencedLists, sessionHeap)
|
|
14683
14802
|
]);
|
|
14803
|
+
const hasExplicitArtifacts = allowExplicitArtifacts && (explicitEntries.length > 0 || explicitLists.length > 0);
|
|
14804
|
+
const lists = hasExplicitArtifacts ? explicitLists : jobLists;
|
|
14805
|
+
const entries = hasExplicitArtifacts ? explicitEntries : changedEntries;
|
|
14684
14806
|
const responseText = extractResponseText(result, stdout) || fallbackResponseText(entries, lists);
|
|
14685
14807
|
return {
|
|
14686
14808
|
responseText,
|
|
14687
14809
|
entries,
|
|
14688
14810
|
lists,
|
|
14689
14811
|
changedEntries,
|
|
14690
|
-
changedLists: jobLists
|
|
14812
|
+
changedLists: jobLists,
|
|
14813
|
+
hasExplicitArtifacts
|
|
14814
|
+
};
|
|
14815
|
+
}
|
|
14816
|
+
|
|
14817
|
+
// src/session-transcript.ts
|
|
14818
|
+
var EMPTY_HEAP = {
|
|
14819
|
+
entriesByPath: {},
|
|
14820
|
+
listsByName: {},
|
|
14821
|
+
variablesByName: {}};
|
|
14822
|
+
function asRecord4(value) {
|
|
14823
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
14824
|
+
return value;
|
|
14825
|
+
}
|
|
14826
|
+
function asArray2(value) {
|
|
14827
|
+
return Array.isArray(value) ? value : [];
|
|
14828
|
+
}
|
|
14829
|
+
function asNumber(value) {
|
|
14830
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
14831
|
+
}
|
|
14832
|
+
function asString(value) {
|
|
14833
|
+
return typeof value === "string" ? value : void 0;
|
|
14834
|
+
}
|
|
14835
|
+
function trimString(value) {
|
|
14836
|
+
return typeof value === "string" ? value.trim() : "";
|
|
14837
|
+
}
|
|
14838
|
+
function normalizeShowRefs(value) {
|
|
14839
|
+
const record = asRecord4(value);
|
|
14840
|
+
if (!record) return void 0;
|
|
14841
|
+
const normalizeRefs = (input) => {
|
|
14842
|
+
if (!Array.isArray(input)) return void 0;
|
|
14843
|
+
const refs = Array.from(
|
|
14844
|
+
new Set(
|
|
14845
|
+
input.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean)
|
|
14846
|
+
)
|
|
14847
|
+
);
|
|
14848
|
+
return refs.length > 0 ? refs : void 0;
|
|
14849
|
+
};
|
|
14850
|
+
const show = {
|
|
14851
|
+
entryPaths: normalizeRefs(record.entryPaths),
|
|
14852
|
+
listNames: normalizeRefs(record.listNames),
|
|
14853
|
+
variableNames: normalizeRefs(record.variableNames)
|
|
14854
|
+
};
|
|
14855
|
+
return show.entryPaths || show.listNames || show.variableNames ? show : void 0;
|
|
14856
|
+
}
|
|
14857
|
+
function stringifyTranscriptValue(value, fallback = "") {
|
|
14858
|
+
if (typeof value === "string") {
|
|
14859
|
+
return value.trim() || fallback;
|
|
14860
|
+
}
|
|
14861
|
+
if (typeof value === "boolean") {
|
|
14862
|
+
return value ? "Confirmed" : "Canceled";
|
|
14863
|
+
}
|
|
14864
|
+
if (value === void 0) {
|
|
14865
|
+
return fallback;
|
|
14866
|
+
}
|
|
14867
|
+
try {
|
|
14868
|
+
const json = JSON.stringify(value, null, 2);
|
|
14869
|
+
if (!json || json === "undefined") return fallback;
|
|
14870
|
+
return json.length > 2e3 ? `${json.slice(0, 2e3)}...` : json;
|
|
14871
|
+
} catch {
|
|
14872
|
+
return String(value);
|
|
14873
|
+
}
|
|
14874
|
+
}
|
|
14875
|
+
function buildArtifactHistory(show) {
|
|
14876
|
+
if (!show) return void 0;
|
|
14877
|
+
return `[Agent message]
|
|
14878
|
+
${stringifyTranscriptValue({ show }, "")}`;
|
|
14879
|
+
}
|
|
14880
|
+
function normalizeConversationMessage(raw) {
|
|
14881
|
+
const record = asRecord4(raw);
|
|
14882
|
+
if (!record) return null;
|
|
14883
|
+
const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
|
|
14884
|
+
if (!role) return null;
|
|
14885
|
+
const content = trimString(
|
|
14886
|
+
record.content ?? record.reply ?? record.message ?? record.text
|
|
14887
|
+
);
|
|
14888
|
+
const show = normalizeShowRefs(record.show);
|
|
14889
|
+
const id = asString(record.id) || crypto.randomUUID();
|
|
14890
|
+
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
14891
|
+
if (!content && !show) return null;
|
|
14892
|
+
return {
|
|
14893
|
+
id,
|
|
14894
|
+
role,
|
|
14895
|
+
content,
|
|
14896
|
+
timestamp,
|
|
14897
|
+
jobId: asString(record.jobId),
|
|
14898
|
+
promptId: asString(record.promptId),
|
|
14899
|
+
show,
|
|
14900
|
+
historyContent: role === "assistant" ? content ? `[Assistant reply]
|
|
14901
|
+
${content}` : buildArtifactHistory(show) : void 0,
|
|
14902
|
+
source: "conversation"
|
|
14691
14903
|
};
|
|
14692
14904
|
}
|
|
14905
|
+
function normalizePromptEntries(jobId, rawPrompts, conversationPromptIds) {
|
|
14906
|
+
const promptsById = asRecord4(rawPrompts) || {};
|
|
14907
|
+
return Object.values(promptsById).map((value) => asRecord4(value)).filter((value) => Boolean(value)).sort(
|
|
14908
|
+
(left, right) => (asNumber(left.openedAt) || asNumber(left.answeredAt) || 0) - (asNumber(right.openedAt) || asNumber(right.answeredAt) || 0)
|
|
14909
|
+
).flatMap((prompt) => {
|
|
14910
|
+
const promptId = asString(prompt.promptId);
|
|
14911
|
+
if (!promptId || conversationPromptIds.has(promptId)) return [];
|
|
14912
|
+
const title = trimString(prompt.title);
|
|
14913
|
+
const message = trimString(prompt.message);
|
|
14914
|
+
const assistantContent = message || title || "Input required";
|
|
14915
|
+
const openedAt = asNumber(prompt.openedAt) || 0;
|
|
14916
|
+
const answeredAt = asNumber(prompt.answeredAt) || openedAt;
|
|
14917
|
+
const entries = [
|
|
14918
|
+
{
|
|
14919
|
+
id: `prompt:${promptId}:assistant`,
|
|
14920
|
+
role: "assistant",
|
|
14921
|
+
content: assistantContent,
|
|
14922
|
+
timestamp: openedAt,
|
|
14923
|
+
jobId,
|
|
14924
|
+
promptId,
|
|
14925
|
+
historyContent: `[Assistant reply]
|
|
14926
|
+
${assistantContent}`,
|
|
14927
|
+
source: "job_prompt"
|
|
14928
|
+
}
|
|
14929
|
+
];
|
|
14930
|
+
if (Object.prototype.hasOwnProperty.call(prompt, "answer")) {
|
|
14931
|
+
entries.push({
|
|
14932
|
+
id: `prompt:${promptId}:user`,
|
|
14933
|
+
role: "user",
|
|
14934
|
+
content: stringifyTranscriptValue(prompt.answer, ""),
|
|
14935
|
+
timestamp: answeredAt,
|
|
14936
|
+
jobId,
|
|
14937
|
+
promptId,
|
|
14938
|
+
source: "job_prompt"
|
|
14939
|
+
});
|
|
14940
|
+
}
|
|
14941
|
+
return entries;
|
|
14942
|
+
});
|
|
14943
|
+
}
|
|
14944
|
+
function normalizeAgentMessageEntries(jobId, rawMessages) {
|
|
14945
|
+
return asArray2(rawMessages).map((value) => asRecord4(value)).filter((value) => Boolean(value)).sort(
|
|
14946
|
+
(left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
|
|
14947
|
+
).flatMap((message) => {
|
|
14948
|
+
const messageId = asString(message.messageId) || asString(message.id) || crypto.randomUUID();
|
|
14949
|
+
const timestamp = asNumber(message.timestamp) || asNumber(message.ts) || 0;
|
|
14950
|
+
const reply = trimString(
|
|
14951
|
+
message.reply ?? message.message ?? message.text ?? message.content
|
|
14952
|
+
);
|
|
14953
|
+
const show = normalizeShowRefs(message.show);
|
|
14954
|
+
const entries = [];
|
|
14955
|
+
if (reply) {
|
|
14956
|
+
entries.push({
|
|
14957
|
+
id: `agent:${messageId}:text`,
|
|
14958
|
+
role: "assistant",
|
|
14959
|
+
content: reply,
|
|
14960
|
+
timestamp,
|
|
14961
|
+
jobId,
|
|
14962
|
+
historyContent: `[Assistant reply]
|
|
14963
|
+
${reply}`,
|
|
14964
|
+
source: "job_agent_message"
|
|
14965
|
+
});
|
|
14966
|
+
}
|
|
14967
|
+
if (show) {
|
|
14968
|
+
entries.push({
|
|
14969
|
+
id: `agent:${messageId}:artifacts`,
|
|
14970
|
+
role: "assistant",
|
|
14971
|
+
content: "",
|
|
14972
|
+
timestamp,
|
|
14973
|
+
jobId,
|
|
14974
|
+
show,
|
|
14975
|
+
historyContent: buildArtifactHistory(show),
|
|
14976
|
+
source: "job_agent_message"
|
|
14977
|
+
});
|
|
14978
|
+
}
|
|
14979
|
+
return entries;
|
|
14980
|
+
});
|
|
14981
|
+
}
|
|
14982
|
+
function buildJobFallbackEntries(jobId, job, sessionHeap) {
|
|
14983
|
+
const timestamp = asNumber(job.finishedAt) || asNumber(job.startedAt) || asNumber(job.submittedAt) || 0;
|
|
14984
|
+
const resultPreview = stringifyTranscriptValue(
|
|
14985
|
+
job.result,
|
|
14986
|
+
"No job result recorded."
|
|
14987
|
+
);
|
|
14988
|
+
const presentation = resolveJobPresentation({
|
|
14989
|
+
jobId,
|
|
14990
|
+
result: job.result,
|
|
14991
|
+
stdout: [],
|
|
14992
|
+
sessionHeap
|
|
14993
|
+
});
|
|
14994
|
+
const entries = [];
|
|
14995
|
+
const responseText = presentation.responseText || "";
|
|
14996
|
+
if (responseText) {
|
|
14997
|
+
entries.push({
|
|
14998
|
+
id: `job:${jobId}:result-text`,
|
|
14999
|
+
role: "assistant",
|
|
15000
|
+
content: responseText,
|
|
15001
|
+
timestamp,
|
|
15002
|
+
jobId,
|
|
15003
|
+
historyContent: `[Assistant reply]
|
|
15004
|
+
${responseText}`,
|
|
15005
|
+
source: "job_result"
|
|
15006
|
+
});
|
|
15007
|
+
}
|
|
15008
|
+
const show = {
|
|
15009
|
+
entryPaths: presentation.entries.map((entry) => entry.path),
|
|
15010
|
+
listNames: presentation.lists.map((list) => list.name)
|
|
15011
|
+
};
|
|
15012
|
+
if (show.entryPaths && show.entryPaths.length > 0 || show.listNames && show.listNames.length > 0) {
|
|
15013
|
+
entries.push({
|
|
15014
|
+
id: `job:${jobId}:result-artifacts`,
|
|
15015
|
+
role: "assistant",
|
|
15016
|
+
content: "",
|
|
15017
|
+
timestamp,
|
|
15018
|
+
jobId,
|
|
15019
|
+
show,
|
|
15020
|
+
historyContent: buildArtifactHistory(show),
|
|
15021
|
+
source: "job_result"
|
|
15022
|
+
});
|
|
15023
|
+
}
|
|
15024
|
+
if (entries.length === 0 && trimString(job.error)) {
|
|
15025
|
+
entries.push({
|
|
15026
|
+
id: `job:${jobId}:result-error`,
|
|
15027
|
+
role: "assistant",
|
|
15028
|
+
content: trimString(job.error),
|
|
15029
|
+
timestamp,
|
|
15030
|
+
jobId,
|
|
15031
|
+
historyContent: `[Assistant reply]
|
|
15032
|
+
${trimString(job.error)}`,
|
|
15033
|
+
source: "job_result"
|
|
15034
|
+
});
|
|
15035
|
+
}
|
|
15036
|
+
if (entries.length === 0 && resultPreview && resultPreview !== "No job result recorded.") {
|
|
15037
|
+
entries.push({
|
|
15038
|
+
id: `job:${jobId}:result-preview`,
|
|
15039
|
+
role: "assistant",
|
|
15040
|
+
content: resultPreview,
|
|
15041
|
+
timestamp,
|
|
15042
|
+
jobId,
|
|
15043
|
+
historyContent: `[Assistant reply]
|
|
15044
|
+
${resultPreview}`,
|
|
15045
|
+
source: "job_result"
|
|
15046
|
+
});
|
|
15047
|
+
}
|
|
15048
|
+
return entries;
|
|
15049
|
+
}
|
|
15050
|
+
function buildJobCodeEntry(jobId, job) {
|
|
15051
|
+
const code = trimString(job.source);
|
|
15052
|
+
if (!code) return null;
|
|
15053
|
+
const jobStatus = asString(job.status);
|
|
15054
|
+
const error = jobStatus === "failed" || jobStatus === "canceled" || jobStatus === "timeout" ? trimString(job.error) || `Job ${jobStatus}` : void 0;
|
|
15055
|
+
return {
|
|
15056
|
+
id: `job:${jobId}:code`,
|
|
15057
|
+
role: "assistant",
|
|
15058
|
+
content: "",
|
|
15059
|
+
timestamp: asNumber(job.submittedAt) || asNumber(job.startedAt) || asNumber(job.finishedAt) || 0,
|
|
15060
|
+
jobId,
|
|
15061
|
+
code,
|
|
15062
|
+
jobStatus,
|
|
15063
|
+
jobResultPreview: stringifyTranscriptValue(job.result, "No job result recorded."),
|
|
15064
|
+
error,
|
|
15065
|
+
source: "job_code"
|
|
15066
|
+
};
|
|
15067
|
+
}
|
|
15068
|
+
function buildSessionTranscript(input) {
|
|
15069
|
+
const liveDoc = input.liveDoc || null;
|
|
15070
|
+
const sessionHeap = input.sessionHeap || EMPTY_HEAP;
|
|
15071
|
+
const transcript = [];
|
|
15072
|
+
const conversationMessages = asArray2(asRecord4(liveDoc?.conversation)?.messages).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
|
|
15073
|
+
const conversationPromptIds = new Set(
|
|
15074
|
+
conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
|
|
15075
|
+
);
|
|
15076
|
+
const assistantConversationJobIds = new Set(
|
|
15077
|
+
conversationMessages.filter((message) => message.role === "assistant" && Boolean(message.jobId)).map((message) => message.jobId)
|
|
15078
|
+
);
|
|
15079
|
+
transcript.push(...conversationMessages);
|
|
15080
|
+
const jobsById = asRecord4(asRecord4(liveDoc?.jobs)?.byId) || {};
|
|
15081
|
+
const jobs = Object.values(jobsById).map((value) => asRecord4(value)).filter((value) => Boolean(value)).sort(
|
|
15082
|
+
(left, right) => (asNumber(left.submittedAt) || asNumber(left.startedAt) || asNumber(left.finishedAt) || 0) - (asNumber(right.submittedAt) || asNumber(right.startedAt) || asNumber(right.finishedAt) || 0)
|
|
15083
|
+
);
|
|
15084
|
+
for (const job of jobs) {
|
|
15085
|
+
const jobId = asString(job.jobId);
|
|
15086
|
+
if (!jobId) continue;
|
|
15087
|
+
const codeEntry = buildJobCodeEntry(jobId, job);
|
|
15088
|
+
if (codeEntry) {
|
|
15089
|
+
transcript.push(codeEntry);
|
|
15090
|
+
}
|
|
15091
|
+
transcript.push(
|
|
15092
|
+
...normalizePromptEntries(jobId, job.prompts, conversationPromptIds)
|
|
15093
|
+
);
|
|
15094
|
+
if (!assistantConversationJobIds.has(jobId)) {
|
|
15095
|
+
const agentEntries = normalizeAgentMessageEntries(jobId, job.agentMessages);
|
|
15096
|
+
if (agentEntries.length > 0) {
|
|
15097
|
+
transcript.push(...agentEntries);
|
|
15098
|
+
} else {
|
|
15099
|
+
transcript.push(
|
|
15100
|
+
...buildJobFallbackEntries(
|
|
15101
|
+
jobId,
|
|
15102
|
+
job,
|
|
15103
|
+
sessionHeap
|
|
15104
|
+
)
|
|
15105
|
+
);
|
|
15106
|
+
}
|
|
15107
|
+
}
|
|
15108
|
+
}
|
|
15109
|
+
return transcript.sort((left, right) => {
|
|
15110
|
+
if (left.timestamp !== right.timestamp) {
|
|
15111
|
+
return left.timestamp - right.timestamp;
|
|
15112
|
+
}
|
|
15113
|
+
return left.id.localeCompare(right.id);
|
|
15114
|
+
});
|
|
15115
|
+
}
|
|
14693
15116
|
|
|
14694
15117
|
exports.Environment = Environment;
|
|
14695
15118
|
exports.Granular = Granular;
|
|
@@ -14704,6 +15127,7 @@ exports.buildGranularAgentSessionBlock = buildGranularAgentSessionBlock;
|
|
|
14704
15127
|
exports.buildGranularAgentSystemPrompt = buildGranularAgentSystemPrompt;
|
|
14705
15128
|
exports.buildGranularAgentToolBlock = buildGranularAgentToolBlock;
|
|
14706
15129
|
exports.buildGranularAgentWorkflowBlock = buildGranularAgentWorkflowBlock;
|
|
15130
|
+
exports.buildSessionTranscript = buildSessionTranscript;
|
|
14707
15131
|
exports.createHarnessVerifierSnapshot = createHarnessVerifierSnapshot;
|
|
14708
15132
|
exports.evaluateContinuation = evaluateContinuation;
|
|
14709
15133
|
exports.extractPromptTokens = extractPromptTokens;
|