@granular-software/sdk 0.4.32 → 0.4.34
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 +21 -0
- package/dist/agent-evals.d.mts +1 -1
- package/dist/agent-evals.d.ts +1 -1
- package/dist/agent-evals.js +859 -316
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +859 -316
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/cli/index.js +828 -30
- package/dist/{client-C2Gk641P.d.mts → client-iw76FL_8.d.mts} +153 -34
- package/dist/{client-C2Gk641P.d.ts → client-iw76FL_8.d.ts} +153 -34
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9363 -9120
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9363 -9120
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -15222,7 +15222,8 @@ ${effectMetamodelTable}
|
|
|
15222
15222
|
| \`getDomain()\`, \`getDomainTypes()\`, \`getDomainDocs()\`, \`getDomainDocumentation()\` | Domain summary and generated TypeScript / docs. |
|
|
15223
15223
|
| \`getEffects()\` / \`getTools()\`, \`session.on("effects:changed", ...)\` | Effect catalog and live updates. |
|
|
15224
15224
|
| \`checkReadiness()\`, \`on('readiness', ...)\` | Runtime readiness. |
|
|
15225
|
-
| \`getHeap()\` |
|
|
15225
|
+
| \`document\`, \`getHeap()\` | Current live session state from the WebSocket. |
|
|
15226
|
+
| \`messages.list()\`, \`timeline.list()\`, \`jobs.list/get()\`, \`heap.entries.list/get()\`, \`heap.lists.list/get()\`, \`transcript.list()\` | Durable session history and saved artifacts. |
|
|
15226
15227
|
| \`disconnect()\` | Close the live runtime session. |
|
|
15227
15228
|
| \`rpc(method, params)\` | Low-level session RPC (advanced). |
|
|
15228
15229
|
| \`disconnect()\` | End the session. |
|
|
@@ -19413,6 +19414,540 @@ var JobImplementation = class {
|
|
|
19413
19414
|
}
|
|
19414
19415
|
};
|
|
19415
19416
|
|
|
19417
|
+
// src/job-presentation.ts
|
|
19418
|
+
var RESPONSE_KEYS = [
|
|
19419
|
+
"reply",
|
|
19420
|
+
"response",
|
|
19421
|
+
"text",
|
|
19422
|
+
"message",
|
|
19423
|
+
"summary",
|
|
19424
|
+
"answer"
|
|
19425
|
+
];
|
|
19426
|
+
var ENTRY_KEY_CANDIDATES = ["entryPath", "path"];
|
|
19427
|
+
var ENTRY_ARRAY_KEY_CANDIDATES = ["entryPaths", "paths"];
|
|
19428
|
+
var LIST_KEY_CANDIDATES = ["listName"];
|
|
19429
|
+
var LIST_ARRAY_KEY_CANDIDATES = ["listNames"];
|
|
19430
|
+
var VARIABLE_KEY_CANDIDATES = ["variableName"];
|
|
19431
|
+
var VARIABLE_ARRAY_KEY_CANDIDATES = ["variableNames"];
|
|
19432
|
+
var UI_CONTAINER_KEYS = ["show", "display", "present", "ui"];
|
|
19433
|
+
function asRecord2(value) {
|
|
19434
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
19435
|
+
return value;
|
|
19436
|
+
}
|
|
19437
|
+
function normalizeText(value) {
|
|
19438
|
+
if (typeof value !== "string") return null;
|
|
19439
|
+
const trimmed = value.trim();
|
|
19440
|
+
if (!trimmed) return null;
|
|
19441
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
19442
|
+
return null;
|
|
19443
|
+
}
|
|
19444
|
+
return trimmed;
|
|
19445
|
+
}
|
|
19446
|
+
function humanTextFromStdout(stdout) {
|
|
19447
|
+
for (const line of [...stdout].reverse()) {
|
|
19448
|
+
const normalized = normalizeText(line);
|
|
19449
|
+
if (!normalized) continue;
|
|
19450
|
+
if (/^[A-Z_]+:/.test(normalized)) continue;
|
|
19451
|
+
return normalized;
|
|
19452
|
+
}
|
|
19453
|
+
return null;
|
|
19454
|
+
}
|
|
19455
|
+
function pushString(target, value) {
|
|
19456
|
+
if (typeof value === "string" && value.trim()) {
|
|
19457
|
+
target.add(value.trim());
|
|
19458
|
+
}
|
|
19459
|
+
}
|
|
19460
|
+
function pushStringArray(target, value) {
|
|
19461
|
+
if (!Array.isArray(value)) return;
|
|
19462
|
+
for (const item of value) {
|
|
19463
|
+
pushString(target, item);
|
|
19464
|
+
}
|
|
19465
|
+
}
|
|
19466
|
+
function collectReferencesFromRecord(record, refs) {
|
|
19467
|
+
for (const key of ENTRY_KEY_CANDIDATES)
|
|
19468
|
+
pushString(refs.entryPaths, record[key]);
|
|
19469
|
+
for (const key of ENTRY_ARRAY_KEY_CANDIDATES)
|
|
19470
|
+
pushStringArray(refs.entryPaths, record[key]);
|
|
19471
|
+
for (const key of LIST_KEY_CANDIDATES)
|
|
19472
|
+
pushString(refs.listNames, record[key]);
|
|
19473
|
+
for (const key of LIST_ARRAY_KEY_CANDIDATES)
|
|
19474
|
+
pushStringArray(refs.listNames, record[key]);
|
|
19475
|
+
for (const key of VARIABLE_KEY_CANDIDATES)
|
|
19476
|
+
pushString(refs.variableNames, record[key]);
|
|
19477
|
+
for (const key of VARIABLE_ARRAY_KEY_CANDIDATES)
|
|
19478
|
+
pushStringArray(refs.variableNames, record[key]);
|
|
19479
|
+
}
|
|
19480
|
+
function scanForHeapReferences(value, heap, refs, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
19481
|
+
if (value === null || value === void 0 || depth > 4 || seen.has(value))
|
|
19482
|
+
return;
|
|
19483
|
+
if (typeof value === "string") {
|
|
19484
|
+
const trimmed = value.trim();
|
|
19485
|
+
if (heap.entriesByPath?.[trimmed]) refs.entryPaths.add(trimmed);
|
|
19486
|
+
if (heap.listsByName?.[trimmed]) refs.listNames.add(trimmed);
|
|
19487
|
+
if (heap.variablesByName?.[trimmed]) refs.variableNames.add(trimmed);
|
|
19488
|
+
return;
|
|
19489
|
+
}
|
|
19490
|
+
if (Array.isArray(value)) {
|
|
19491
|
+
seen.add(value);
|
|
19492
|
+
for (const item of value.slice(0, 24)) {
|
|
19493
|
+
scanForHeapReferences(item, heap, refs, depth + 1, seen);
|
|
19494
|
+
}
|
|
19495
|
+
return;
|
|
19496
|
+
}
|
|
19497
|
+
const record = asRecord2(value);
|
|
19498
|
+
if (!record) return;
|
|
19499
|
+
seen.add(value);
|
|
19500
|
+
collectReferencesFromRecord(record, refs);
|
|
19501
|
+
for (const key of UI_CONTAINER_KEYS) {
|
|
19502
|
+
const nested = asRecord2(record[key]);
|
|
19503
|
+
if (nested) collectReferencesFromRecord(nested, refs);
|
|
19504
|
+
}
|
|
19505
|
+
for (const nested of Object.values(record).slice(0, 24)) {
|
|
19506
|
+
scanForHeapReferences(nested, heap, refs, depth + 1, seen);
|
|
19507
|
+
}
|
|
19508
|
+
}
|
|
19509
|
+
function resolveVariablesToReferences(variableNames, heap, refs) {
|
|
19510
|
+
for (const variableName of variableNames) {
|
|
19511
|
+
const variable = heap.variablesByName?.[variableName];
|
|
19512
|
+
if (!variable) continue;
|
|
19513
|
+
if (variable.kind === "entry" && variable.entryPath) {
|
|
19514
|
+
refs.entryPaths.add(variable.entryPath);
|
|
19515
|
+
}
|
|
19516
|
+
if (variable.kind === "list" && variable.listName) {
|
|
19517
|
+
refs.listNames.add(variable.listName);
|
|
19518
|
+
}
|
|
19519
|
+
}
|
|
19520
|
+
}
|
|
19521
|
+
function sortEntries(entries) {
|
|
19522
|
+
return [...entries].sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
|
|
19523
|
+
}
|
|
19524
|
+
function sortLists(lists) {
|
|
19525
|
+
return [...lists].sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
|
|
19526
|
+
}
|
|
19527
|
+
function dedupeEntries(entries) {
|
|
19528
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19529
|
+
const result = [];
|
|
19530
|
+
for (const entry of entries) {
|
|
19531
|
+
if (!entry?.path || seen.has(entry.path)) continue;
|
|
19532
|
+
seen.add(entry.path);
|
|
19533
|
+
result.push(entry);
|
|
19534
|
+
}
|
|
19535
|
+
return result;
|
|
19536
|
+
}
|
|
19537
|
+
function dedupeLists(lists) {
|
|
19538
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19539
|
+
const result = [];
|
|
19540
|
+
for (const list of lists) {
|
|
19541
|
+
if (!list?.name || seen.has(list.name)) continue;
|
|
19542
|
+
seen.add(list.name);
|
|
19543
|
+
result.push(list);
|
|
19544
|
+
}
|
|
19545
|
+
return result;
|
|
19546
|
+
}
|
|
19547
|
+
function extractResponseText(result, stdout) {
|
|
19548
|
+
const directText = normalizeText(result);
|
|
19549
|
+
if (directText) return directText;
|
|
19550
|
+
const record = asRecord2(result);
|
|
19551
|
+
if (record) {
|
|
19552
|
+
for (const key of RESPONSE_KEYS) {
|
|
19553
|
+
const normalized = normalizeText(record[key]);
|
|
19554
|
+
if (normalized) return normalized;
|
|
19555
|
+
}
|
|
19556
|
+
for (const containerKey of UI_CONTAINER_KEYS) {
|
|
19557
|
+
const nested = asRecord2(record[containerKey]);
|
|
19558
|
+
if (!nested) continue;
|
|
19559
|
+
for (const key of RESPONSE_KEYS) {
|
|
19560
|
+
const normalized = normalizeText(nested[key]);
|
|
19561
|
+
if (normalized) return normalized;
|
|
19562
|
+
}
|
|
19563
|
+
}
|
|
19564
|
+
}
|
|
19565
|
+
return humanTextFromStdout(stdout);
|
|
19566
|
+
}
|
|
19567
|
+
function fallbackResponseText(entries, lists) {
|
|
19568
|
+
if (entries.length > 0) {
|
|
19569
|
+
return entries.length === 1 ? "I found one relevant record." : `I found ${entries.length} relevant records.`;
|
|
19570
|
+
}
|
|
19571
|
+
if (lists.length > 0) {
|
|
19572
|
+
const emptyOnly = lists.every((list) => (list.paths || []).length === 0);
|
|
19573
|
+
if (emptyOnly) {
|
|
19574
|
+
return lists.length === 1 ? "I saved one empty result set." : `I saved ${lists.length} empty result sets.`;
|
|
19575
|
+
}
|
|
19576
|
+
return lists.length === 1 ? "I saved one result set." : `I saved ${lists.length} result sets.`;
|
|
19577
|
+
}
|
|
19578
|
+
return null;
|
|
19579
|
+
}
|
|
19580
|
+
function getJobRelatedEntries(heap, jobId) {
|
|
19581
|
+
return sortEntries(
|
|
19582
|
+
Object.values(heap.entriesByPath || {}).filter(
|
|
19583
|
+
(entry) => entry.relatedJobIds?.includes(jobId)
|
|
19584
|
+
)
|
|
19585
|
+
);
|
|
19586
|
+
}
|
|
19587
|
+
function getJobRelatedLists(heap, jobId) {
|
|
19588
|
+
return sortLists(
|
|
19589
|
+
Object.values(heap.listsByName || {}).filter(
|
|
19590
|
+
(list) => list.relatedJobIds?.includes(jobId)
|
|
19591
|
+
)
|
|
19592
|
+
);
|
|
19593
|
+
}
|
|
19594
|
+
function entriesFromLists(lists, heap) {
|
|
19595
|
+
const entries = [];
|
|
19596
|
+
for (const list of lists) {
|
|
19597
|
+
for (const path6 of list.paths || []) {
|
|
19598
|
+
const entry = heap.entriesByPath?.[path6];
|
|
19599
|
+
if (entry) entries.push(entry);
|
|
19600
|
+
}
|
|
19601
|
+
}
|
|
19602
|
+
return entries;
|
|
19603
|
+
}
|
|
19604
|
+
function resolveJobPresentation({
|
|
19605
|
+
jobId,
|
|
19606
|
+
result,
|
|
19607
|
+
stdout = [],
|
|
19608
|
+
sessionHeap,
|
|
19609
|
+
allowExplicitArtifacts = true
|
|
19610
|
+
}) {
|
|
19611
|
+
const refs = {
|
|
19612
|
+
entryPaths: /* @__PURE__ */ new Set(),
|
|
19613
|
+
listNames: /* @__PURE__ */ new Set(),
|
|
19614
|
+
variableNames: /* @__PURE__ */ new Set()
|
|
19615
|
+
};
|
|
19616
|
+
if (allowExplicitArtifacts) {
|
|
19617
|
+
scanForHeapReferences(result, sessionHeap, refs);
|
|
19618
|
+
resolveVariablesToReferences(refs.variableNames, sessionHeap, refs);
|
|
19619
|
+
}
|
|
19620
|
+
const referencedLists = sortLists(
|
|
19621
|
+
[...refs.listNames].map((name) => sessionHeap.listsByName?.[name]).filter((list) => Boolean(list))
|
|
19622
|
+
);
|
|
19623
|
+
const referencedEntries = sortEntries(
|
|
19624
|
+
[...refs.entryPaths].map((path6) => sessionHeap.entriesByPath?.[path6]).filter((entry) => Boolean(entry))
|
|
19625
|
+
);
|
|
19626
|
+
const jobLists = getJobRelatedLists(sessionHeap, jobId);
|
|
19627
|
+
const jobEntries = getJobRelatedEntries(sessionHeap, jobId);
|
|
19628
|
+
const changedEntries = dedupeEntries([
|
|
19629
|
+
...jobEntries,
|
|
19630
|
+
...entriesFromLists(jobLists, sessionHeap)
|
|
19631
|
+
]);
|
|
19632
|
+
const explicitLists = dedupeLists(referencedLists);
|
|
19633
|
+
const explicitEntries = dedupeEntries([
|
|
19634
|
+
...referencedEntries,
|
|
19635
|
+
...entriesFromLists(referencedLists, sessionHeap)
|
|
19636
|
+
]);
|
|
19637
|
+
const hasExplicitArtifacts = allowExplicitArtifacts && (explicitEntries.length > 0 || explicitLists.length > 0);
|
|
19638
|
+
const lists = hasExplicitArtifacts ? explicitLists : jobLists;
|
|
19639
|
+
const entries = hasExplicitArtifacts ? explicitEntries : changedEntries;
|
|
19640
|
+
const responseText = extractResponseText(result, stdout) || fallbackResponseText(entries, lists);
|
|
19641
|
+
return {
|
|
19642
|
+
responseText,
|
|
19643
|
+
entries,
|
|
19644
|
+
lists,
|
|
19645
|
+
changedEntries,
|
|
19646
|
+
changedLists: jobLists,
|
|
19647
|
+
hasExplicitArtifacts
|
|
19648
|
+
};
|
|
19649
|
+
}
|
|
19650
|
+
|
|
19651
|
+
// src/session-transcript.ts
|
|
19652
|
+
var EMPTY_HEAP = {
|
|
19653
|
+
entriesByPath: {},
|
|
19654
|
+
listsByName: {},
|
|
19655
|
+
variablesByName: {}};
|
|
19656
|
+
function asRecord3(value) {
|
|
19657
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
19658
|
+
return value;
|
|
19659
|
+
}
|
|
19660
|
+
function asArray(value) {
|
|
19661
|
+
return Array.isArray(value) ? value : [];
|
|
19662
|
+
}
|
|
19663
|
+
function asNumber(value) {
|
|
19664
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
19665
|
+
}
|
|
19666
|
+
function asString(value) {
|
|
19667
|
+
return typeof value === "string" ? value : void 0;
|
|
19668
|
+
}
|
|
19669
|
+
function trimString(value) {
|
|
19670
|
+
return typeof value === "string" ? value.trim() : "";
|
|
19671
|
+
}
|
|
19672
|
+
function normalizeShowRefs(value) {
|
|
19673
|
+
const record = asRecord3(value);
|
|
19674
|
+
if (!record) return void 0;
|
|
19675
|
+
const normalizeRefs = (input) => {
|
|
19676
|
+
if (!Array.isArray(input)) return void 0;
|
|
19677
|
+
const refs = Array.from(
|
|
19678
|
+
new Set(
|
|
19679
|
+
input.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean)
|
|
19680
|
+
)
|
|
19681
|
+
);
|
|
19682
|
+
return refs.length > 0 ? refs : void 0;
|
|
19683
|
+
};
|
|
19684
|
+
const show = {
|
|
19685
|
+
entryPaths: normalizeRefs(record.entryPaths),
|
|
19686
|
+
listNames: normalizeRefs(record.listNames),
|
|
19687
|
+
variableNames: normalizeRefs(record.variableNames)
|
|
19688
|
+
};
|
|
19689
|
+
return show.entryPaths || show.listNames || show.variableNames ? show : void 0;
|
|
19690
|
+
}
|
|
19691
|
+
function stringifyTranscriptValue(value, fallback2 = "") {
|
|
19692
|
+
if (typeof value === "string") {
|
|
19693
|
+
return value.trim() || fallback2;
|
|
19694
|
+
}
|
|
19695
|
+
if (typeof value === "boolean") {
|
|
19696
|
+
return value ? "Confirmed" : "Canceled";
|
|
19697
|
+
}
|
|
19698
|
+
if (value === void 0) {
|
|
19699
|
+
return fallback2;
|
|
19700
|
+
}
|
|
19701
|
+
try {
|
|
19702
|
+
const json = JSON.stringify(value, null, 2);
|
|
19703
|
+
if (!json || json === "undefined") return fallback2;
|
|
19704
|
+
return json.length > 2e3 ? `${json.slice(0, 2e3)}...` : json;
|
|
19705
|
+
} catch {
|
|
19706
|
+
return String(value);
|
|
19707
|
+
}
|
|
19708
|
+
}
|
|
19709
|
+
function buildArtifactHistory(show) {
|
|
19710
|
+
if (!show) return void 0;
|
|
19711
|
+
return `[Agent message]
|
|
19712
|
+
${stringifyTranscriptValue({ show }, "")}`;
|
|
19713
|
+
}
|
|
19714
|
+
function normalizeConversationMessage(raw) {
|
|
19715
|
+
const record = asRecord3(raw);
|
|
19716
|
+
if (!record) return null;
|
|
19717
|
+
const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
|
|
19718
|
+
if (!role) return null;
|
|
19719
|
+
const content = trimString(
|
|
19720
|
+
record.content ?? record.reply ?? record.message ?? record.text
|
|
19721
|
+
);
|
|
19722
|
+
const show = normalizeShowRefs(record.show);
|
|
19723
|
+
const id = asString(record.id) || crypto.randomUUID();
|
|
19724
|
+
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
19725
|
+
if (!content && !show) return null;
|
|
19726
|
+
return {
|
|
19727
|
+
id,
|
|
19728
|
+
role,
|
|
19729
|
+
content,
|
|
19730
|
+
timestamp,
|
|
19731
|
+
jobId: asString(record.jobId),
|
|
19732
|
+
promptId: asString(record.promptId),
|
|
19733
|
+
show,
|
|
19734
|
+
historyContent: role === "assistant" ? content ? `[Assistant reply]
|
|
19735
|
+
${content}` : buildArtifactHistory(show) : void 0,
|
|
19736
|
+
source: "conversation"
|
|
19737
|
+
};
|
|
19738
|
+
}
|
|
19739
|
+
function normalizePromptEntries(jobId, rawPrompts, conversationPromptIds) {
|
|
19740
|
+
const promptsById = asRecord3(rawPrompts) || {};
|
|
19741
|
+
return Object.values(promptsById).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
19742
|
+
(left, right) => (asNumber(left.openedAt) || asNumber(left.answeredAt) || 0) - (asNumber(right.openedAt) || asNumber(right.answeredAt) || 0)
|
|
19743
|
+
).flatMap((prompt3) => {
|
|
19744
|
+
const promptId = asString(prompt3.promptId);
|
|
19745
|
+
if (!promptId || conversationPromptIds.has(promptId)) return [];
|
|
19746
|
+
const title = trimString(prompt3.title);
|
|
19747
|
+
const message = trimString(prompt3.message);
|
|
19748
|
+
const assistantContent = message || title || "Input required";
|
|
19749
|
+
const openedAt = asNumber(prompt3.openedAt) || 0;
|
|
19750
|
+
const answeredAt = asNumber(prompt3.answeredAt) || openedAt;
|
|
19751
|
+
const entries = [
|
|
19752
|
+
{
|
|
19753
|
+
id: `prompt:${promptId}:assistant`,
|
|
19754
|
+
role: "assistant",
|
|
19755
|
+
content: assistantContent,
|
|
19756
|
+
timestamp: openedAt,
|
|
19757
|
+
jobId,
|
|
19758
|
+
promptId,
|
|
19759
|
+
historyContent: `[Assistant reply]
|
|
19760
|
+
${assistantContent}`,
|
|
19761
|
+
source: "job_prompt"
|
|
19762
|
+
}
|
|
19763
|
+
];
|
|
19764
|
+
if (Object.prototype.hasOwnProperty.call(prompt3, "answer")) {
|
|
19765
|
+
entries.push({
|
|
19766
|
+
id: `prompt:${promptId}:user`,
|
|
19767
|
+
role: "user",
|
|
19768
|
+
content: stringifyTranscriptValue(prompt3.answer, ""),
|
|
19769
|
+
timestamp: answeredAt,
|
|
19770
|
+
jobId,
|
|
19771
|
+
promptId,
|
|
19772
|
+
source: "job_prompt"
|
|
19773
|
+
});
|
|
19774
|
+
}
|
|
19775
|
+
return entries;
|
|
19776
|
+
});
|
|
19777
|
+
}
|
|
19778
|
+
function normalizeAgentMessageEntries(jobId, rawMessages) {
|
|
19779
|
+
return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
19780
|
+
(left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
|
|
19781
|
+
).flatMap((message) => {
|
|
19782
|
+
const messageId = asString(message.messageId) || asString(message.id) || crypto.randomUUID();
|
|
19783
|
+
const timestamp = asNumber(message.timestamp) || asNumber(message.ts) || 0;
|
|
19784
|
+
const reply = trimString(
|
|
19785
|
+
message.reply ?? message.message ?? message.text ?? message.content
|
|
19786
|
+
);
|
|
19787
|
+
const show = normalizeShowRefs(message.show);
|
|
19788
|
+
const entries = [];
|
|
19789
|
+
if (reply) {
|
|
19790
|
+
entries.push({
|
|
19791
|
+
id: `agent:${messageId}:text`,
|
|
19792
|
+
role: "assistant",
|
|
19793
|
+
content: reply,
|
|
19794
|
+
timestamp,
|
|
19795
|
+
jobId,
|
|
19796
|
+
historyContent: `[Assistant reply]
|
|
19797
|
+
${reply}`,
|
|
19798
|
+
source: "job_agent_message"
|
|
19799
|
+
});
|
|
19800
|
+
}
|
|
19801
|
+
if (show) {
|
|
19802
|
+
entries.push({
|
|
19803
|
+
id: `agent:${messageId}:artifacts`,
|
|
19804
|
+
role: "assistant",
|
|
19805
|
+
content: "",
|
|
19806
|
+
timestamp,
|
|
19807
|
+
jobId,
|
|
19808
|
+
show,
|
|
19809
|
+
historyContent: buildArtifactHistory(show),
|
|
19810
|
+
source: "job_agent_message"
|
|
19811
|
+
});
|
|
19812
|
+
}
|
|
19813
|
+
return entries;
|
|
19814
|
+
});
|
|
19815
|
+
}
|
|
19816
|
+
function buildJobFallbackEntries(jobId, job2, sessionHeap) {
|
|
19817
|
+
const timestamp = asNumber(job2.finishedAt) || asNumber(job2.startedAt) || asNumber(job2.submittedAt) || 0;
|
|
19818
|
+
const resultPreview = stringifyTranscriptValue(
|
|
19819
|
+
job2.result,
|
|
19820
|
+
"No job result recorded."
|
|
19821
|
+
);
|
|
19822
|
+
const presentation = resolveJobPresentation({
|
|
19823
|
+
jobId,
|
|
19824
|
+
result: job2.result,
|
|
19825
|
+
stdout: [],
|
|
19826
|
+
sessionHeap
|
|
19827
|
+
});
|
|
19828
|
+
const entries = [];
|
|
19829
|
+
const responseText = presentation.responseText || "";
|
|
19830
|
+
if (responseText) {
|
|
19831
|
+
entries.push({
|
|
19832
|
+
id: `job:${jobId}:result-text`,
|
|
19833
|
+
role: "assistant",
|
|
19834
|
+
content: responseText,
|
|
19835
|
+
timestamp,
|
|
19836
|
+
jobId,
|
|
19837
|
+
historyContent: `[Assistant reply]
|
|
19838
|
+
${responseText}`,
|
|
19839
|
+
source: "job_result"
|
|
19840
|
+
});
|
|
19841
|
+
}
|
|
19842
|
+
const show = {
|
|
19843
|
+
entryPaths: presentation.entries.map((entry) => entry.path),
|
|
19844
|
+
listNames: presentation.lists.map((list) => list.name)
|
|
19845
|
+
};
|
|
19846
|
+
if (show.entryPaths && show.entryPaths.length > 0 || show.listNames && show.listNames.length > 0) {
|
|
19847
|
+
entries.push({
|
|
19848
|
+
id: `job:${jobId}:result-artifacts`,
|
|
19849
|
+
role: "assistant",
|
|
19850
|
+
content: "",
|
|
19851
|
+
timestamp,
|
|
19852
|
+
jobId,
|
|
19853
|
+
show,
|
|
19854
|
+
historyContent: buildArtifactHistory(show),
|
|
19855
|
+
source: "job_result"
|
|
19856
|
+
});
|
|
19857
|
+
}
|
|
19858
|
+
if (entries.length === 0 && trimString(job2.error)) {
|
|
19859
|
+
entries.push({
|
|
19860
|
+
id: `job:${jobId}:result-error`,
|
|
19861
|
+
role: "assistant",
|
|
19862
|
+
content: trimString(job2.error),
|
|
19863
|
+
timestamp,
|
|
19864
|
+
jobId,
|
|
19865
|
+
historyContent: `[Assistant reply]
|
|
19866
|
+
${trimString(job2.error)}`,
|
|
19867
|
+
source: "job_result"
|
|
19868
|
+
});
|
|
19869
|
+
}
|
|
19870
|
+
if (entries.length === 0 && resultPreview && resultPreview !== "No job result recorded.") {
|
|
19871
|
+
entries.push({
|
|
19872
|
+
id: `job:${jobId}:result-preview`,
|
|
19873
|
+
role: "assistant",
|
|
19874
|
+
content: resultPreview,
|
|
19875
|
+
timestamp,
|
|
19876
|
+
jobId,
|
|
19877
|
+
historyContent: `[Assistant reply]
|
|
19878
|
+
${resultPreview}`,
|
|
19879
|
+
source: "job_result"
|
|
19880
|
+
});
|
|
19881
|
+
}
|
|
19882
|
+
return entries;
|
|
19883
|
+
}
|
|
19884
|
+
function buildJobCodeEntry(jobId, job2) {
|
|
19885
|
+
const code = trimString(job2.source);
|
|
19886
|
+
if (!code) return null;
|
|
19887
|
+
const jobStatus = asString(job2.status);
|
|
19888
|
+
const error2 = jobStatus === "failed" || jobStatus === "canceled" || jobStatus === "timeout" ? trimString(job2.error) || `Job ${jobStatus}` : void 0;
|
|
19889
|
+
return {
|
|
19890
|
+
id: `job:${jobId}:code`,
|
|
19891
|
+
role: "assistant",
|
|
19892
|
+
content: "",
|
|
19893
|
+
timestamp: asNumber(job2.submittedAt) || asNumber(job2.startedAt) || asNumber(job2.finishedAt) || 0,
|
|
19894
|
+
jobId,
|
|
19895
|
+
code,
|
|
19896
|
+
jobStatus,
|
|
19897
|
+
jobResultPreview: stringifyTranscriptValue(job2.result, "No job result recorded."),
|
|
19898
|
+
error: error2,
|
|
19899
|
+
source: "job_code"
|
|
19900
|
+
};
|
|
19901
|
+
}
|
|
19902
|
+
function buildSessionTranscript(input) {
|
|
19903
|
+
const liveDoc = input.liveDoc || null;
|
|
19904
|
+
const sessionHeap = input.sessionHeap || EMPTY_HEAP;
|
|
19905
|
+
const transcript = [];
|
|
19906
|
+
const conversationMessages = asArray(asRecord3(liveDoc?.conversation)?.messages).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
|
|
19907
|
+
const conversationPromptIds = new Set(
|
|
19908
|
+
conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
|
|
19909
|
+
);
|
|
19910
|
+
const assistantConversationJobIds = new Set(
|
|
19911
|
+
conversationMessages.filter((message) => message.role === "assistant" && Boolean(message.jobId)).map((message) => message.jobId)
|
|
19912
|
+
);
|
|
19913
|
+
transcript.push(...conversationMessages);
|
|
19914
|
+
const jobsById = asRecord3(asRecord3(liveDoc?.jobs)?.byId) || {};
|
|
19915
|
+
const jobs = Object.values(jobsById).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
|
|
19916
|
+
(left, right) => (asNumber(left.submittedAt) || asNumber(left.startedAt) || asNumber(left.finishedAt) || 0) - (asNumber(right.submittedAt) || asNumber(right.startedAt) || asNumber(right.finishedAt) || 0)
|
|
19917
|
+
);
|
|
19918
|
+
for (const job2 of jobs) {
|
|
19919
|
+
const jobId = asString(job2.jobId);
|
|
19920
|
+
if (!jobId) continue;
|
|
19921
|
+
const codeEntry = buildJobCodeEntry(jobId, job2);
|
|
19922
|
+
if (codeEntry) {
|
|
19923
|
+
transcript.push(codeEntry);
|
|
19924
|
+
}
|
|
19925
|
+
transcript.push(
|
|
19926
|
+
...normalizePromptEntries(jobId, job2.prompts, conversationPromptIds)
|
|
19927
|
+
);
|
|
19928
|
+
if (!assistantConversationJobIds.has(jobId)) {
|
|
19929
|
+
const agentEntries = normalizeAgentMessageEntries(jobId, job2.agentMessages);
|
|
19930
|
+
if (agentEntries.length > 0) {
|
|
19931
|
+
transcript.push(...agentEntries);
|
|
19932
|
+
} else {
|
|
19933
|
+
transcript.push(
|
|
19934
|
+
...buildJobFallbackEntries(
|
|
19935
|
+
jobId,
|
|
19936
|
+
job2,
|
|
19937
|
+
sessionHeap
|
|
19938
|
+
)
|
|
19939
|
+
);
|
|
19940
|
+
}
|
|
19941
|
+
}
|
|
19942
|
+
}
|
|
19943
|
+
return transcript.sort((left, right) => {
|
|
19944
|
+
if (left.timestamp !== right.timestamp) {
|
|
19945
|
+
return left.timestamp - right.timestamp;
|
|
19946
|
+
}
|
|
19947
|
+
return left.id.localeCompare(right.id);
|
|
19948
|
+
});
|
|
19949
|
+
}
|
|
19950
|
+
|
|
19416
19951
|
// src/effect-runtime.ts
|
|
19417
19952
|
function computeEffectKey(effect) {
|
|
19418
19953
|
const attachedClass = effect.className?.trim();
|
|
@@ -19421,6 +19956,50 @@ function computeEffectKey(effect) {
|
|
|
19421
19956
|
}
|
|
19422
19957
|
return effect.static ? `class:${attachedClass}:static:${effect.name}` : `class:${attachedClass}:instance:${effect.name}`;
|
|
19423
19958
|
}
|
|
19959
|
+
function computeEffectVersionSelectorSpecificity(selector) {
|
|
19960
|
+
if (!selector || selector.mode === "all") {
|
|
19961
|
+
return 0;
|
|
19962
|
+
}
|
|
19963
|
+
if (selector.mode === "exact") {
|
|
19964
|
+
return 2;
|
|
19965
|
+
}
|
|
19966
|
+
return 1;
|
|
19967
|
+
}
|
|
19968
|
+
function matchesEffectVersionSelector(selector, buildVersionNumber) {
|
|
19969
|
+
if (!selector || selector.mode === "all") {
|
|
19970
|
+
return true;
|
|
19971
|
+
}
|
|
19972
|
+
if (typeof buildVersionNumber !== "number" || !Number.isFinite(buildVersionNumber)) {
|
|
19973
|
+
return false;
|
|
19974
|
+
}
|
|
19975
|
+
if (selector.mode === "exact") {
|
|
19976
|
+
return buildVersionNumber === selector.versionNumber;
|
|
19977
|
+
}
|
|
19978
|
+
if (selector.mode === "before") {
|
|
19979
|
+
return buildVersionNumber < selector.versionNumber;
|
|
19980
|
+
}
|
|
19981
|
+
return buildVersionNumber > selector.versionNumber;
|
|
19982
|
+
}
|
|
19983
|
+
function selectRegisteredEffect(effectMap, effectKey, buildVersionNumber) {
|
|
19984
|
+
let bestEffect;
|
|
19985
|
+
let bestSpecificity = Number.NEGATIVE_INFINITY;
|
|
19986
|
+
for (const effect of effectMap.values()) {
|
|
19987
|
+
if (computeEffectKey(effect) !== effectKey) {
|
|
19988
|
+
continue;
|
|
19989
|
+
}
|
|
19990
|
+
if (!matchesEffectVersionSelector(effect.versionSelector, buildVersionNumber)) {
|
|
19991
|
+
continue;
|
|
19992
|
+
}
|
|
19993
|
+
const specificity = computeEffectVersionSelectorSpecificity(
|
|
19994
|
+
effect.versionSelector
|
|
19995
|
+
);
|
|
19996
|
+
if (!bestEffect || specificity > bestSpecificity) {
|
|
19997
|
+
bestEffect = effect;
|
|
19998
|
+
bestSpecificity = specificity;
|
|
19999
|
+
}
|
|
20000
|
+
}
|
|
20001
|
+
return bestEffect;
|
|
20002
|
+
}
|
|
19424
20003
|
function normalizeEffectBehaviors(value) {
|
|
19425
20004
|
return normalizeEffectBehaviorSummary(
|
|
19426
20005
|
value
|
|
@@ -19441,9 +20020,17 @@ function resolveReverseEffect(effectMap, currentEffect, request, behaviors) {
|
|
|
19441
20020
|
return void 0;
|
|
19442
20021
|
}
|
|
19443
20022
|
if (reverseHandler.includes(":")) {
|
|
19444
|
-
return
|
|
20023
|
+
return selectRegisteredEffect(
|
|
20024
|
+
effectMap,
|
|
20025
|
+
reverseHandler,
|
|
20026
|
+
request.context?.buildVersionNumber
|
|
20027
|
+
);
|
|
19445
20028
|
}
|
|
19446
|
-
const directMatch =
|
|
20029
|
+
const directMatch = selectRegisteredEffect(
|
|
20030
|
+
effectMap,
|
|
20031
|
+
reverseHandler,
|
|
20032
|
+
request.context?.buildVersionNumber
|
|
20033
|
+
);
|
|
19447
20034
|
if (directMatch) {
|
|
19448
20035
|
return directMatch;
|
|
19449
20036
|
}
|
|
@@ -19458,7 +20045,11 @@ function resolveReverseEffect(effectMap, currentEffect, request, behaviors) {
|
|
|
19458
20045
|
})
|
|
19459
20046
|
];
|
|
19460
20047
|
for (const candidateKey of candidateKeys) {
|
|
19461
|
-
const candidate =
|
|
20048
|
+
const candidate = selectRegisteredEffect(
|
|
20049
|
+
effectMap,
|
|
20050
|
+
candidateKey,
|
|
20051
|
+
request.context?.buildVersionNumber
|
|
20052
|
+
);
|
|
19462
20053
|
if (candidate) {
|
|
19463
20054
|
return candidate;
|
|
19464
20055
|
}
|
|
@@ -19494,7 +20085,11 @@ function resolveHandlerForMode(effectMap, effect, request) {
|
|
|
19494
20085
|
return { effect, mode, handler: effect.handler };
|
|
19495
20086
|
}
|
|
19496
20087
|
async function invokeRegisteredEffect(effectMap, request) {
|
|
19497
|
-
const effect =
|
|
20088
|
+
const effect = selectRegisteredEffect(
|
|
20089
|
+
effectMap,
|
|
20090
|
+
request.effectKey,
|
|
20091
|
+
request.context?.buildVersionNumber
|
|
20092
|
+
);
|
|
19498
20093
|
if (!effect) {
|
|
19499
20094
|
throw new Error(`Effect handler not found: ${request.effectKey}`);
|
|
19500
20095
|
}
|
|
@@ -19615,6 +20210,17 @@ function computeEffectKey2(effect) {
|
|
|
19615
20210
|
}
|
|
19616
20211
|
return effect.static ? `class:${attachedClass}:static:${effect.name}` : `class:${attachedClass}:instance:${effect.name}`;
|
|
19617
20212
|
}
|
|
20213
|
+
function computeEffectVersionSelectorKey(selector) {
|
|
20214
|
+
if (!selector || selector.mode === "all") {
|
|
20215
|
+
return "all";
|
|
20216
|
+
}
|
|
20217
|
+
return `${selector.mode}:${selector.versionNumber}`;
|
|
20218
|
+
}
|
|
20219
|
+
function computeEffectRegistrationKey(effect) {
|
|
20220
|
+
return `${computeEffectKey2(effect)}@${computeEffectVersionSelectorKey(
|
|
20221
|
+
effect.versionSelector
|
|
20222
|
+
)}`;
|
|
20223
|
+
}
|
|
19618
20224
|
function buildEffectHostUrl(apiUrl, sandboxId, effectClientId, clientId) {
|
|
19619
20225
|
const url = new URL(apiUrl);
|
|
19620
20226
|
if (url.pathname.endsWith("/granular/ws/connect")) {
|
|
@@ -20109,7 +20715,9 @@ var Environment = class {
|
|
|
20109
20715
|
{ target: targetPath }
|
|
20110
20716
|
);
|
|
20111
20717
|
if (result.errors?.length) {
|
|
20112
|
-
throw new Error(
|
|
20718
|
+
throw new Error(
|
|
20719
|
+
`attach failed: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`
|
|
20720
|
+
);
|
|
20113
20721
|
}
|
|
20114
20722
|
}
|
|
20115
20723
|
/**
|
|
@@ -20144,7 +20752,9 @@ var Environment = class {
|
|
|
20144
20752
|
}`
|
|
20145
20753
|
);
|
|
20146
20754
|
if (result.errors?.length) {
|
|
20147
|
-
throw new Error(
|
|
20755
|
+
throw new Error(
|
|
20756
|
+
`detach failed: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`
|
|
20757
|
+
);
|
|
20148
20758
|
}
|
|
20149
20759
|
}
|
|
20150
20760
|
/**
|
|
@@ -20266,7 +20876,9 @@ var Environment = class {
|
|
|
20266
20876
|
async _runGraphql(query, label) {
|
|
20267
20877
|
const result = await this.graphql(query);
|
|
20268
20878
|
if (result.errors?.length) {
|
|
20269
|
-
throw new Error(
|
|
20879
|
+
throw new Error(
|
|
20880
|
+
`${label}: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`
|
|
20881
|
+
);
|
|
20270
20882
|
}
|
|
20271
20883
|
return result.data;
|
|
20272
20884
|
}
|
|
@@ -20801,6 +21413,9 @@ var EnvironmentSession = class extends Session {
|
|
|
20801
21413
|
get envName() {
|
|
20802
21414
|
return this.environment.envName;
|
|
20803
21415
|
}
|
|
21416
|
+
get tag() {
|
|
21417
|
+
return this.environment.tag;
|
|
21418
|
+
}
|
|
20804
21419
|
get versionId() {
|
|
20805
21420
|
return this.environment.versionId;
|
|
20806
21421
|
}
|
|
@@ -20820,12 +21435,171 @@ var EnvironmentSession = class extends Session {
|
|
|
20820
21435
|
return this.environment.feedback;
|
|
20821
21436
|
}
|
|
20822
21437
|
/**
|
|
20823
|
-
* Return a plain JS
|
|
21438
|
+
* Return a plain JS copy of the synced session heap.
|
|
20824
21439
|
*/
|
|
20825
21440
|
getHeap() {
|
|
20826
21441
|
const doc = this.document;
|
|
20827
21442
|
return normalizeHeapSnapshot(doc?.heap);
|
|
20828
21443
|
}
|
|
21444
|
+
async sessionDataRequest(path6, query) {
|
|
21445
|
+
const searchParams = new URLSearchParams();
|
|
21446
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
21447
|
+
if (value !== null && typeof value !== "undefined" && value !== "") {
|
|
21448
|
+
searchParams.set(key, String(value));
|
|
21449
|
+
}
|
|
21450
|
+
}
|
|
21451
|
+
const queryString = searchParams.toString();
|
|
21452
|
+
const response = await fetch(
|
|
21453
|
+
`${this.environment.runtimeBaseUrl}/orchestrator/ws/sessions/${encodeURIComponent(this.sessionId)}${path6}${queryString ? `?${queryString}` : ""}`,
|
|
21454
|
+
{
|
|
21455
|
+
method: "GET",
|
|
21456
|
+
headers: {
|
|
21457
|
+
Authorization: `Bearer ${this.environment.authToken}`,
|
|
21458
|
+
"Content-Type": "application/json"
|
|
21459
|
+
}
|
|
21460
|
+
}
|
|
21461
|
+
);
|
|
21462
|
+
if (!response.ok) {
|
|
21463
|
+
const errorText = await response.text();
|
|
21464
|
+
throw new Error(
|
|
21465
|
+
`Session data API Error (${response.status}): ${errorText}`
|
|
21466
|
+
);
|
|
21467
|
+
}
|
|
21468
|
+
return response.json();
|
|
21469
|
+
}
|
|
21470
|
+
async collectAllSessionItems(listPage) {
|
|
21471
|
+
const items = [];
|
|
21472
|
+
let cursor = null;
|
|
21473
|
+
do {
|
|
21474
|
+
const page = await listPage({ limit: 500, cursor });
|
|
21475
|
+
items.push(...page.items);
|
|
21476
|
+
cursor = page.nextCursor;
|
|
21477
|
+
} while (cursor);
|
|
21478
|
+
return items;
|
|
21479
|
+
}
|
|
21480
|
+
/**
|
|
21481
|
+
* Fetch the live session document from the runtime DO.
|
|
21482
|
+
*
|
|
21483
|
+
* For history and saved artifacts, prefer the collection APIs on
|
|
21484
|
+
* `messages`, `timeline`, `jobs`, and `heap`.
|
|
21485
|
+
*/
|
|
21486
|
+
async getDocument() {
|
|
21487
|
+
return this.sessionDataRequest("/document");
|
|
21488
|
+
}
|
|
21489
|
+
get messages() {
|
|
21490
|
+
return {
|
|
21491
|
+
list: (options = {}) => this.sessionDataRequest(
|
|
21492
|
+
"/messages",
|
|
21493
|
+
options
|
|
21494
|
+
)
|
|
21495
|
+
};
|
|
21496
|
+
}
|
|
21497
|
+
get timeline() {
|
|
21498
|
+
return {
|
|
21499
|
+
list: (options = {}) => this.sessionDataRequest(
|
|
21500
|
+
"/timeline",
|
|
21501
|
+
options
|
|
21502
|
+
)
|
|
21503
|
+
};
|
|
21504
|
+
}
|
|
21505
|
+
get jobs() {
|
|
21506
|
+
return {
|
|
21507
|
+
list: (options = {}) => this.sessionDataRequest(
|
|
21508
|
+
"/jobs",
|
|
21509
|
+
options
|
|
21510
|
+
),
|
|
21511
|
+
get: (jobId) => this.sessionDataRequest(
|
|
21512
|
+
`/jobs/${encodeURIComponent(jobId)}`
|
|
21513
|
+
)
|
|
21514
|
+
};
|
|
21515
|
+
}
|
|
21516
|
+
get heap() {
|
|
21517
|
+
return {
|
|
21518
|
+
entries: {
|
|
21519
|
+
list: (options = {}) => this.sessionDataRequest(
|
|
21520
|
+
"/heap/entries",
|
|
21521
|
+
options
|
|
21522
|
+
),
|
|
21523
|
+
get: (path6) => this.sessionDataRequest(
|
|
21524
|
+
`/heap/entries/${encodeURIComponent(path6)}`
|
|
21525
|
+
)
|
|
21526
|
+
},
|
|
21527
|
+
lists: {
|
|
21528
|
+
list: (options = {}) => this.sessionDataRequest(
|
|
21529
|
+
"/heap/lists",
|
|
21530
|
+
options
|
|
21531
|
+
),
|
|
21532
|
+
get: (name) => this.sessionDataRequest(
|
|
21533
|
+
`/heap/lists/${encodeURIComponent(name)}`
|
|
21534
|
+
)
|
|
21535
|
+
}
|
|
21536
|
+
};
|
|
21537
|
+
}
|
|
21538
|
+
get transcript() {
|
|
21539
|
+
return {
|
|
21540
|
+
list: async (options = {}) => {
|
|
21541
|
+
const [messages, jobs, entries, lists] = await Promise.all([
|
|
21542
|
+
this.collectAllSessionItems(this.messages.list),
|
|
21543
|
+
this.collectAllSessionItems(
|
|
21544
|
+
(pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
|
|
21545
|
+
),
|
|
21546
|
+
this.collectAllSessionItems(this.heap.entries.list),
|
|
21547
|
+
this.collectAllSessionItems(this.heap.lists.list)
|
|
21548
|
+
]);
|
|
21549
|
+
const liveDoc = {
|
|
21550
|
+
conversation: { messages },
|
|
21551
|
+
jobs: {
|
|
21552
|
+
byId: Object.fromEntries(
|
|
21553
|
+
jobs.map((job2) => {
|
|
21554
|
+
const record = job2 && typeof job2 === "object" ? job2 : null;
|
|
21555
|
+
const id = typeof record?.jobId === "string" ? record.jobId : typeof record?.id === "string" ? record.id : null;
|
|
21556
|
+
return id ? [id, record] : null;
|
|
21557
|
+
}).filter(
|
|
21558
|
+
(entry) => Boolean(entry)
|
|
21559
|
+
)
|
|
21560
|
+
)
|
|
21561
|
+
}
|
|
21562
|
+
};
|
|
21563
|
+
const heap = normalizeHeapSnapshot({
|
|
21564
|
+
entriesByPath: Object.fromEntries(
|
|
21565
|
+
entries.map((entry) => {
|
|
21566
|
+
return entry?.path ? [
|
|
21567
|
+
entry.path,
|
|
21568
|
+
entry
|
|
21569
|
+
] : null;
|
|
21570
|
+
}).filter(
|
|
21571
|
+
(entry) => Boolean(entry)
|
|
21572
|
+
)
|
|
21573
|
+
),
|
|
21574
|
+
listsByName: Object.fromEntries(
|
|
21575
|
+
lists.map((list) => {
|
|
21576
|
+
return list?.name ? [list.name, list] : null;
|
|
21577
|
+
}).filter(
|
|
21578
|
+
(entry) => Boolean(entry)
|
|
21579
|
+
)
|
|
21580
|
+
),
|
|
21581
|
+
variablesByName: this.getHeap().variablesByName,
|
|
21582
|
+
updatedAt: Date.now()
|
|
21583
|
+
});
|
|
21584
|
+
const allItems = buildSessionTranscript({
|
|
21585
|
+
liveDoc,
|
|
21586
|
+
sessionHeap: heap
|
|
21587
|
+
});
|
|
21588
|
+
const limit = Math.max(
|
|
21589
|
+
1,
|
|
21590
|
+
Math.min(500, Math.floor(options.limit ?? 100))
|
|
21591
|
+
);
|
|
21592
|
+
const offset = typeof options.cursor === "string" ? Number.parseInt(options.cursor, 10) || 0 : 0;
|
|
21593
|
+
const items = allItems.slice(offset, offset + limit);
|
|
21594
|
+
const nextOffset = offset + items.length;
|
|
21595
|
+
return {
|
|
21596
|
+
items,
|
|
21597
|
+
nextCursor: nextOffset < allItems.length ? String(nextOffset) : null,
|
|
21598
|
+
totalCount: allItems.length
|
|
21599
|
+
};
|
|
21600
|
+
}
|
|
21601
|
+
};
|
|
21602
|
+
}
|
|
20829
21603
|
async graphql(query, variables) {
|
|
20830
21604
|
return this.environment.graphql(query, variables);
|
|
20831
21605
|
}
|
|
@@ -20968,7 +21742,7 @@ var Granular = class _Granular {
|
|
|
20968
21742
|
onUnexpectedClose;
|
|
20969
21743
|
onReconnectError;
|
|
20970
21744
|
debugHttp = process.env.GRANULAR_DEBUG_HTTP === "1";
|
|
20971
|
-
/** Sandbox-level effect registry: sandboxId → (effectKey → ToolWithHandler) */
|
|
21745
|
+
/** Sandbox-level effect registry: sandboxId → (effectKey@selector → ToolWithHandler) */
|
|
20972
21746
|
sandboxEffects = /* @__PURE__ */ new Map();
|
|
20973
21747
|
/** Live sandbox-scoped effect hosts keyed by sandboxId */
|
|
20974
21748
|
sandboxEffectHosts = /* @__PURE__ */ new Map();
|
|
@@ -21387,7 +22161,8 @@ var Granular = class _Granular {
|
|
|
21387
22161
|
provenance: effect.provenance || { source: "custom" },
|
|
21388
22162
|
tags: effect.tags,
|
|
21389
22163
|
className: effect.className,
|
|
21390
|
-
static: effect.static
|
|
22164
|
+
static: effect.static,
|
|
22165
|
+
versionSelector: effect.versionSelector
|
|
21391
22166
|
};
|
|
21392
22167
|
}
|
|
21393
22168
|
async publishSandboxEffectCatalog(host) {
|
|
@@ -21575,7 +22350,10 @@ var Granular = class _Granular {
|
|
|
21575
22350
|
async registerEffect(sandboxNameOrId, effect) {
|
|
21576
22351
|
const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
|
|
21577
22352
|
const sandboxId = sandbox.sandboxId;
|
|
21578
|
-
this.getSandboxEffectMap(sandboxId).set(
|
|
22353
|
+
this.getSandboxEffectMap(sandboxId).set(
|
|
22354
|
+
computeEffectRegistrationKey(effect),
|
|
22355
|
+
effect
|
|
22356
|
+
);
|
|
21579
22357
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
21580
22358
|
}
|
|
21581
22359
|
/**
|
|
@@ -21588,7 +22366,7 @@ var Granular = class _Granular {
|
|
|
21588
22366
|
const sandboxId = sandbox.sandboxId;
|
|
21589
22367
|
const map = this.getSandboxEffectMap(sandboxId);
|
|
21590
22368
|
for (const effect of effects2) {
|
|
21591
|
-
map.set(
|
|
22369
|
+
map.set(computeEffectRegistrationKey(effect), effect);
|
|
21592
22370
|
}
|
|
21593
22371
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
21594
22372
|
}
|
|
@@ -21606,7 +22384,7 @@ var Granular = class _Granular {
|
|
|
21606
22384
|
return;
|
|
21607
22385
|
}
|
|
21608
22386
|
const nextEntries = Array.from(currentMap.entries()).filter(
|
|
21609
|
-
([
|
|
22387
|
+
([, effect]) => computeEffectKey2(effect) !== name && effect.name !== name
|
|
21610
22388
|
);
|
|
21611
22389
|
if (nextEntries.length === currentMap.size) {
|
|
21612
22390
|
return;
|
|
@@ -22053,14 +22831,18 @@ async function resolveOntologyId(granular, ontology) {
|
|
|
22053
22831
|
const { config } = createGranularClient();
|
|
22054
22832
|
const requestedOntology = ontology ?? config.sandboxId;
|
|
22055
22833
|
if (!requestedOntology) {
|
|
22056
|
-
throw new Error(
|
|
22834
|
+
throw new Error(
|
|
22835
|
+
"No ontology configured. Run `granular init` first or pass `--ontology`."
|
|
22836
|
+
);
|
|
22057
22837
|
}
|
|
22058
22838
|
try {
|
|
22059
22839
|
const sandbox = await granular.sandboxes.get(requestedOntology);
|
|
22060
22840
|
return sandbox.sandboxId;
|
|
22061
22841
|
} catch {
|
|
22062
22842
|
const sandboxes = await granular.sandboxes.list();
|
|
22063
|
-
const existing = sandboxes.items.find(
|
|
22843
|
+
const existing = sandboxes.items.find(
|
|
22844
|
+
(item) => item.name === requestedOntology
|
|
22845
|
+
);
|
|
22064
22846
|
if (existing) {
|
|
22065
22847
|
return existing.sandboxId;
|
|
22066
22848
|
}
|
|
@@ -22068,7 +22850,8 @@ async function resolveOntologyId(granular, ontology) {
|
|
|
22068
22850
|
throw new Error(`Ontology not found: ${requestedOntology}`);
|
|
22069
22851
|
}
|
|
22070
22852
|
function matchesEnvironmentName(environment, requested) {
|
|
22071
|
-
|
|
22853
|
+
const managedPrefix = `__sdk__${requested}__`;
|
|
22854
|
+
return environment.environment === requested || environment.envName === requested || environment.environment?.startsWith(managedPrefix) || environment.envName?.startsWith(managedPrefix) || environment.tag?.name === requested || environment.buildPolicy?.tagName === requested || environment.tracking?.tagName === requested;
|
|
22072
22855
|
}
|
|
22073
22856
|
async function resolveEnvironmentData(granular, options) {
|
|
22074
22857
|
if (options.environmentId) {
|
|
@@ -22077,7 +22860,9 @@ async function resolveEnvironmentData(granular, options) {
|
|
|
22077
22860
|
const ontologyId = await resolveOntologyId(granular, options.ontology);
|
|
22078
22861
|
const environmentName = options.environment ?? "dev";
|
|
22079
22862
|
const environments = await granular.environments.list(ontologyId);
|
|
22080
|
-
const existing = environments.find(
|
|
22863
|
+
const existing = environments.find(
|
|
22864
|
+
(environment) => matchesEnvironmentName(environment, environmentName)
|
|
22865
|
+
);
|
|
22081
22866
|
if (existing) {
|
|
22082
22867
|
return existing;
|
|
22083
22868
|
}
|
|
@@ -22109,7 +22894,9 @@ async function listSessionsForEnvironment(granular, environmentId, status) {
|
|
|
22109
22894
|
async function connectRuntime(options) {
|
|
22110
22895
|
if (options.sessionId) {
|
|
22111
22896
|
const { granular: granular2 } = createGranularClient();
|
|
22112
|
-
const environment2 = await granular2.connectSession({
|
|
22897
|
+
const environment2 = await granular2.connectSession({
|
|
22898
|
+
sessionId: options.sessionId
|
|
22899
|
+
});
|
|
22113
22900
|
return {
|
|
22114
22901
|
granular: granular2,
|
|
22115
22902
|
environment: environment2,
|
|
@@ -22120,7 +22907,9 @@ async function connectRuntime(options) {
|
|
|
22120
22907
|
const { granular, config } = createGranularClient();
|
|
22121
22908
|
const ontologyId = options.ontology ?? config.sandboxId;
|
|
22122
22909
|
if (!ontologyId) {
|
|
22123
|
-
throw new Error(
|
|
22910
|
+
throw new Error(
|
|
22911
|
+
"No ontology configured. Run `granular init` first or pass `--ontology`."
|
|
22912
|
+
);
|
|
22124
22913
|
}
|
|
22125
22914
|
const environmentHandle = await granular.connect({
|
|
22126
22915
|
ontology: ontologyId,
|
|
@@ -22171,13 +22960,14 @@ function readJobCodeFromOptions(options) {
|
|
|
22171
22960
|
// src/cli/commands/connect.ts
|
|
22172
22961
|
async function connectTestCommand(options) {
|
|
22173
22962
|
const emitJson = options.json === true;
|
|
22963
|
+
const requestedEnvironment = options.environment ?? "dev";
|
|
22174
22964
|
if (!emitJson) {
|
|
22175
22965
|
printHeader();
|
|
22176
22966
|
}
|
|
22177
22967
|
await withRuntimeConnection(
|
|
22178
22968
|
{
|
|
22179
22969
|
ontology: options.ontology,
|
|
22180
|
-
environment:
|
|
22970
|
+
environment: requestedEnvironment,
|
|
22181
22971
|
userId: options.user,
|
|
22182
22972
|
permissions: normalizePermissions(options.permissions)
|
|
22183
22973
|
},
|
|
@@ -22187,7 +22977,7 @@ async function connectTestCommand(options) {
|
|
|
22187
22977
|
ontologyId,
|
|
22188
22978
|
sandboxId: environment.sandboxId,
|
|
22189
22979
|
environmentId: environment.environmentId,
|
|
22190
|
-
environment: environment.
|
|
22980
|
+
environment: environment.tag || requestedEnvironment,
|
|
22191
22981
|
sessionId: environment.sessionId,
|
|
22192
22982
|
subjectId: environment.subjectId,
|
|
22193
22983
|
versionId: environment.versionId
|
|
@@ -22200,7 +22990,7 @@ async function connectTestCommand(options) {
|
|
|
22200
22990
|
console.log();
|
|
22201
22991
|
keyValue({
|
|
22202
22992
|
"Ontology ID": payload.ontologyId,
|
|
22203
|
-
|
|
22993
|
+
Environment: payload.environment,
|
|
22204
22994
|
"Environment ID": payload.environmentId,
|
|
22205
22995
|
"Session ID": payload.sessionId,
|
|
22206
22996
|
"Subject ID": payload.subjectId,
|
|
@@ -22267,7 +23057,9 @@ async function sessionDocCommand(options) {
|
|
|
22267
23057
|
ontologyId,
|
|
22268
23058
|
sessionId: environment.sessionId,
|
|
22269
23059
|
environmentId: environment.environmentId,
|
|
22270
|
-
document: documentToJson(
|
|
23060
|
+
document: documentToJson(
|
|
23061
|
+
environment.document
|
|
23062
|
+
)
|
|
22271
23063
|
};
|
|
22272
23064
|
if (!emitJson) {
|
|
22273
23065
|
step("Session document");
|
|
@@ -22279,6 +23071,7 @@ async function sessionDocCommand(options) {
|
|
|
22279
23071
|
}
|
|
22280
23072
|
async function sessionCreateCommand(options) {
|
|
22281
23073
|
const emitJson = options.json === true;
|
|
23074
|
+
const requestedEnvironment = options.environment ?? "dev";
|
|
22282
23075
|
if (!emitJson) {
|
|
22283
23076
|
printHeader();
|
|
22284
23077
|
}
|
|
@@ -22286,7 +23079,7 @@ async function sessionCreateCommand(options) {
|
|
|
22286
23079
|
const permissions = normalizePermissions(options.permissions);
|
|
22287
23080
|
const envData = await resolveEnvironmentData(granular, {
|
|
22288
23081
|
ontology: options.ontology,
|
|
22289
|
-
environment:
|
|
23082
|
+
environment: requestedEnvironment,
|
|
22290
23083
|
environmentId: options.environmentId,
|
|
22291
23084
|
userId: options.user,
|
|
22292
23085
|
permissions,
|
|
@@ -22300,7 +23093,7 @@ async function sessionCreateCommand(options) {
|
|
|
22300
23093
|
ok: true,
|
|
22301
23094
|
ontologyId: envData.sandboxId,
|
|
22302
23095
|
environmentId: environment.environmentId,
|
|
22303
|
-
environment: environment.
|
|
23096
|
+
environment: environment.tag || envData.tag?.name || envData.buildPolicy.tagName || requestedEnvironment,
|
|
22304
23097
|
sessionId: environment.sessionId,
|
|
22305
23098
|
subjectId: environment.subjectId,
|
|
22306
23099
|
versionId: environment.versionId
|
|
@@ -22313,7 +23106,7 @@ async function sessionCreateCommand(options) {
|
|
|
22313
23106
|
console.log();
|
|
22314
23107
|
keyValue({
|
|
22315
23108
|
"Ontology ID": payload.ontologyId,
|
|
22316
|
-
|
|
23109
|
+
Environment: payload.environment,
|
|
22317
23110
|
"Environment ID": payload.environmentId,
|
|
22318
23111
|
"Session ID": payload.sessionId,
|
|
22319
23112
|
"Subject ID": payload.subjectId,
|
|
@@ -22331,21 +23124,26 @@ async function sessionCreateCommand(options) {
|
|
|
22331
23124
|
async function sessionListCommand(options) {
|
|
22332
23125
|
const emitJson = options.json === true;
|
|
22333
23126
|
const status = options.status ?? "active";
|
|
23127
|
+
const requestedEnvironment = options.environment ?? "dev";
|
|
22334
23128
|
if (!emitJson) {
|
|
22335
23129
|
printHeader();
|
|
22336
23130
|
}
|
|
22337
23131
|
const { granular } = createGranularClient();
|
|
22338
23132
|
const environmentData = await resolveEnvironmentData(granular, {
|
|
22339
23133
|
ontology: options.ontology,
|
|
22340
|
-
environment:
|
|
23134
|
+
environment: requestedEnvironment,
|
|
22341
23135
|
environmentId: options.environmentId,
|
|
22342
23136
|
createIfMissing: false
|
|
22343
23137
|
});
|
|
22344
|
-
const items = await listSessionsForEnvironment(
|
|
23138
|
+
const items = await listSessionsForEnvironment(
|
|
23139
|
+
granular,
|
|
23140
|
+
environmentData.environmentId,
|
|
23141
|
+
status
|
|
23142
|
+
);
|
|
22345
23143
|
const payload = {
|
|
22346
23144
|
ontologyId: environmentData.sandboxId,
|
|
22347
23145
|
environmentId: environmentData.environmentId,
|
|
22348
|
-
environment: environmentData.
|
|
23146
|
+
environment: environmentData.tag?.name || environmentData.buildPolicy.tagName || requestedEnvironment,
|
|
22349
23147
|
status,
|
|
22350
23148
|
items
|
|
22351
23149
|
};
|