@granular-software/sdk 0.4.57 → 0.4.59
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 +38 -4
- package/dist/agent-evals.d.mts +2 -3
- package/dist/agent-evals.d.ts +2 -3
- package/dist/agent-evals.js +2992 -1356
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +2992 -1356
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.d.mts +3 -3
- package/dist/agent-harness.d.ts +3 -3
- package/dist/agent-harness.js +67 -131
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +67 -131
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +2619 -1170
- package/dist/{client-BKde5VzV.d.ts → client-BHhqFMeU.d.ts} +91 -21
- package/dist/{client-DL4S9uRc.d.mts → client-aWpvZfX4.d.mts} +91 -21
- package/dist/index.d.mts +33 -11
- package/dist/index.d.ts +33 -11
- package/dist/index.js +2916 -1273
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2902 -1274
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-DpRRCrAr.d.mts → spend-3DNM1u9N.d.mts} +677 -101
- package/dist/{spend-DpRRCrAr.d.ts → spend-3DNM1u9N.d.ts} +677 -101
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/package.json +5 -2
package/dist/agent-harness.mjs
CHANGED
|
@@ -525,7 +525,7 @@ function hasNamedModuleImport(source, moduleName, name) {
|
|
|
525
525
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
526
526
|
const imports = source.matchAll(
|
|
527
527
|
new RegExp(
|
|
528
|
-
`import\\s*\\{([
|
|
528
|
+
`import\\s*\\{([^}]*)\\}\\s*from\\s*['"]${escapedModule}['"]`,
|
|
529
529
|
"g"
|
|
530
530
|
)
|
|
531
531
|
);
|
|
@@ -534,6 +534,22 @@ function hasNamedModuleImport(source, moduleName, name) {
|
|
|
534
534
|
}
|
|
535
535
|
return false;
|
|
536
536
|
}
|
|
537
|
+
function namedModuleImports(source, moduleName) {
|
|
538
|
+
const escapedModule = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
539
|
+
const names = /* @__PURE__ */ new Set();
|
|
540
|
+
for (const match of source.matchAll(
|
|
541
|
+
new RegExp(
|
|
542
|
+
`import\\s*\\{([^}]*)\\}\\s*from\\s*['"]${escapedModule}['"]`,
|
|
543
|
+
"g"
|
|
544
|
+
)
|
|
545
|
+
)) {
|
|
546
|
+
for (const specifier of match[1].split(",")) {
|
|
547
|
+
const imported = specifier.trim().replace(/^type\s+/, "").split(/\s+as\s+/)[0]?.trim();
|
|
548
|
+
if (imported) names.add(imported);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return [...names];
|
|
552
|
+
}
|
|
537
553
|
function hasNamedAgentImport(source, name) {
|
|
538
554
|
return hasNamedModuleImport(source, HARNESS_V3_AGENT_MODULE, name);
|
|
539
555
|
}
|
|
@@ -594,18 +610,54 @@ function reviewGeneratedJobCode(code, _options = {}) {
|
|
|
594
610
|
message: "Generated jobs must not call process.exit(...). Return from the job or emit a runtime message instead."
|
|
595
611
|
});
|
|
596
612
|
}
|
|
613
|
+
const supportedAgentExports = /* @__PURE__ */ new Set([
|
|
614
|
+
"actions",
|
|
615
|
+
"artifacts",
|
|
616
|
+
"feedback",
|
|
617
|
+
"formatBlockers",
|
|
618
|
+
"relativeTime",
|
|
619
|
+
"replyToUser",
|
|
620
|
+
"showAgentResponse",
|
|
621
|
+
"showObjects",
|
|
622
|
+
"table",
|
|
623
|
+
"transientFeedback"
|
|
624
|
+
]);
|
|
625
|
+
for (const imported of namedModuleImports(
|
|
626
|
+
normalized,
|
|
627
|
+
HARNESS_V3_AGENT_MODULE
|
|
628
|
+
)) {
|
|
629
|
+
if (!supportedAgentExports.has(imported)) {
|
|
630
|
+
issues.push({
|
|
631
|
+
code: "unknown_runtime_import",
|
|
632
|
+
severity: "error",
|
|
633
|
+
message: `Generated code imports unknown runtime value \`${imported}\` from ${HARNESS_V3_AGENT_MODULE}. Import only values listed in [Runtime Imports] and [Types].`
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
const removedAgentHelpers = [
|
|
638
|
+
["agent", "text", "message"].join("_"),
|
|
639
|
+
["agent", "heap", "objects"].join("_"),
|
|
640
|
+
["agent", "message"].join("_")
|
|
641
|
+
];
|
|
642
|
+
for (const name of removedAgentHelpers) {
|
|
643
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
644
|
+
if (new RegExp(`\\b${escaped}\\s*\\(`).test(normalized)) {
|
|
645
|
+
issues.push({
|
|
646
|
+
code: "unsupported_runtime_helper",
|
|
647
|
+
severity: "error",
|
|
648
|
+
message: `Generated code calls removed runtime helper \`${name}\`. Import and call only the canonical feed helpers listed for ${HARNESS_V3_AGENT_MODULE}.`
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
597
652
|
for (const [name, replacement, pattern] of [
|
|
598
|
-
["agent_text_message", "replyToUser", /\bagent_text_message\s*\(/],
|
|
599
|
-
["agent_heap_objects", "showObjects", /\bagent_heap_objects\s*\(/],
|
|
600
|
-
["agent_message", "showAgentResponse", /\bagent_message\s*\(/],
|
|
601
653
|
["heap", "groundedObjects", /\bheap\./],
|
|
602
654
|
["loop", "userInteraction or work", /\bloop\./]
|
|
603
655
|
]) {
|
|
604
656
|
if (pattern.test(normalized)) {
|
|
605
657
|
issues.push({
|
|
606
|
-
code: "
|
|
658
|
+
code: "unsupported_runtime_helper",
|
|
607
659
|
severity: "error",
|
|
608
|
-
message: `Generated code uses
|
|
660
|
+
message: `Generated code uses unsupported runtime helper \`${name}\`. Use \`${replacement}\` from the modules listed in [Runtime Imports].`
|
|
609
661
|
});
|
|
610
662
|
}
|
|
611
663
|
}
|
|
@@ -774,116 +826,7 @@ function normalizeActionSummaryForPrompt(line) {
|
|
|
774
826
|
}
|
|
775
827
|
function collectConversationReferents(liveDoc) {
|
|
776
828
|
const conversation = asRecord(liveDoc?.conversation);
|
|
777
|
-
|
|
778
|
-
if (persistedReferents.length > 0) {
|
|
779
|
-
return persistedReferents.slice().sort((left, right) => (right.ts || 0) - (left.ts || 0));
|
|
780
|
-
}
|
|
781
|
-
const heap = asRecord(liveDoc?.heap);
|
|
782
|
-
const entriesByPath = asRecord(heap?.entriesByPath) || {};
|
|
783
|
-
const listsByName = asRecord(heap?.listsByName) || {};
|
|
784
|
-
const variablesByName = asRecord(heap?.variablesByName) || {};
|
|
785
|
-
const messages = asArray(conversation?.messages).map((value) => asRecord(value)).filter((value) => Boolean(value)).slice().sort((left, right) => (Number(right.ts) || 0) - (Number(left.ts) || 0));
|
|
786
|
-
const referents = [];
|
|
787
|
-
const seen = /* @__PURE__ */ new Set();
|
|
788
|
-
const pushReferent = (referent) => {
|
|
789
|
-
if (!referent?.kind || !referent.ref) return;
|
|
790
|
-
const key = `${referent.kind}:${referent.ref}`;
|
|
791
|
-
if (seen.has(key)) return;
|
|
792
|
-
seen.add(key);
|
|
793
|
-
referents.push(referent);
|
|
794
|
-
};
|
|
795
|
-
for (const message of messages) {
|
|
796
|
-
if (message.role !== "assistant") continue;
|
|
797
|
-
const show = asRecord(message.show);
|
|
798
|
-
if (!show) continue;
|
|
799
|
-
const ts = Number(message.ts) || 0;
|
|
800
|
-
const messageId = typeof message.id === "string" ? message.id : void 0;
|
|
801
|
-
const jobId = typeof message.jobId === "string" ? message.jobId : void 0;
|
|
802
|
-
const entryPaths = uniqueStrings(asArray(show.entryPaths));
|
|
803
|
-
const entryClassCounts = /* @__PURE__ */ new Map();
|
|
804
|
-
const entryMetadata = entryPaths.map((entryPath) => {
|
|
805
|
-
const entry = asRecord(entriesByPath[entryPath]);
|
|
806
|
-
const className = typeof entry?.className === "string" ? entry.className : void 0;
|
|
807
|
-
if (className) {
|
|
808
|
-
entryClassCounts.set(
|
|
809
|
-
className,
|
|
810
|
-
(entryClassCounts.get(className) || 0) + 1
|
|
811
|
-
);
|
|
812
|
-
}
|
|
813
|
-
return { entryPath, entry, className };
|
|
814
|
-
});
|
|
815
|
-
const displayGroupId = entryMetadata.length > 1 ? `message:${messageId || jobId || ts}:entries` : void 0;
|
|
816
|
-
for (const [
|
|
817
|
-
index,
|
|
818
|
-
{ entryPath, entry, className }
|
|
819
|
-
] of entryMetadata.entries()) {
|
|
820
|
-
pushReferent({
|
|
821
|
-
id: `entry:${entryPath}`,
|
|
822
|
-
kind: "entry",
|
|
823
|
-
ref: entryPath,
|
|
824
|
-
role: "assistant",
|
|
825
|
-
source: "heap_objects",
|
|
826
|
-
entryPath,
|
|
827
|
-
recordId: typeof entry?.id === "string" ? entry.id : void 0,
|
|
828
|
-
className,
|
|
829
|
-
label: typeof entry?.label === "string" && entry.label.trim() ? entry.label.trim() : typeof entry?.id === "string" && entry.id.trim() ? entry.id.trim() : entryPath,
|
|
830
|
-
...displayGroupId ? {
|
|
831
|
-
displayGroupId,
|
|
832
|
-
displayGroupIndex: index,
|
|
833
|
-
displayGroupSize: entryMetadata.length,
|
|
834
|
-
...className && (entryClassCounts.get(className) || 0) > 1 ? { displayGroupSameTypeSize: entryClassCounts.get(className) } : {}
|
|
835
|
-
} : {},
|
|
836
|
-
messageId,
|
|
837
|
-
jobId,
|
|
838
|
-
ts
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
for (const listName of uniqueStrings(asArray(show.listNames))) {
|
|
842
|
-
const list = asRecord(listsByName[listName]);
|
|
843
|
-
pushReferent({
|
|
844
|
-
id: `list:${listName}`,
|
|
845
|
-
kind: "list",
|
|
846
|
-
ref: listName,
|
|
847
|
-
role: "assistant",
|
|
848
|
-
source: "heap_objects",
|
|
849
|
-
listName,
|
|
850
|
-
className: typeof list?.className === "string" ? list.className : void 0,
|
|
851
|
-
count: Array.isArray(list?.paths) ? list.paths.length : null,
|
|
852
|
-
messageId,
|
|
853
|
-
jobId,
|
|
854
|
-
ts
|
|
855
|
-
});
|
|
856
|
-
}
|
|
857
|
-
for (const variableName of uniqueStrings(
|
|
858
|
-
asArray(show.variableNames)
|
|
859
|
-
)) {
|
|
860
|
-
const variable = asRecord(variablesByName[variableName]);
|
|
861
|
-
const entryPath = typeof variable?.entryPath === "string" ? variable.entryPath : void 0;
|
|
862
|
-
const listName = typeof variable?.listName === "string" ? variable.listName : void 0;
|
|
863
|
-
const entry = entryPath ? asRecord(entriesByPath[entryPath]) : null;
|
|
864
|
-
const list = listName ? asRecord(listsByName[listName]) : null;
|
|
865
|
-
pushReferent({
|
|
866
|
-
id: `variable:${variableName}`,
|
|
867
|
-
kind: "variable",
|
|
868
|
-
ref: variableName,
|
|
869
|
-
role: "assistant",
|
|
870
|
-
source: "heap_objects",
|
|
871
|
-
variableName,
|
|
872
|
-
variableKind: typeof variable?.kind === "string" ? variable.kind : void 0,
|
|
873
|
-
entryPath,
|
|
874
|
-
recordId: typeof entry?.id === "string" ? entry.id : void 0,
|
|
875
|
-
listName,
|
|
876
|
-
className: typeof variable?.className === "string" ? variable.className : typeof entry?.className === "string" ? entry.className : typeof list?.className === "string" ? list.className : void 0,
|
|
877
|
-
label: typeof entry?.label === "string" && entry.label.trim() ? entry.label.trim() : typeof entry?.id === "string" && entry.id.trim() ? entry.id.trim() : null,
|
|
878
|
-
count: variable?.kind === "list" && Array.isArray(list?.paths) ? list.paths.length : null,
|
|
879
|
-
scalarValue: variable?.kind === "scalar" && (typeof variable.value === "string" || typeof variable.value === "number" || typeof variable.value === "boolean" || variable.value === null) ? variable.value : void 0,
|
|
880
|
-
messageId,
|
|
881
|
-
jobId,
|
|
882
|
-
ts
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
return referents;
|
|
829
|
+
return asArray(conversation?.referents).map((value) => asRecord(value)).filter((value) => Boolean(value)).slice().sort((left, right) => (right.ts || 0) - (left.ts || 0));
|
|
887
830
|
}
|
|
888
831
|
function projectConversationReferentFocus(liveDoc) {
|
|
889
832
|
const heap = asRecord(liveDoc?.heap);
|
|
@@ -1677,13 +1620,7 @@ function extractRuntimeContractExports(domainBlock) {
|
|
|
1677
1620
|
}
|
|
1678
1621
|
const actionPattern = /export\s+declare\s+function\s+([A-Za-z_$][\w$]*)/g;
|
|
1679
1622
|
for (const match of domainBlock.matchAll(actionPattern)) {
|
|
1680
|
-
|
|
1681
|
-
if (["agent_text_message", "agent_heap_objects", "agent_message"].includes(
|
|
1682
|
-
name
|
|
1683
|
-
)) {
|
|
1684
|
-
continue;
|
|
1685
|
-
}
|
|
1686
|
-
actions.add(name);
|
|
1623
|
+
actions.add(match[1]);
|
|
1687
1624
|
}
|
|
1688
1625
|
return {
|
|
1689
1626
|
classes: Array.from(classes).sort(),
|
|
@@ -1740,7 +1677,7 @@ function buildGranularAgentRuntimeImportsBlock(input) {
|
|
|
1740
1677
|
importStyle: "named ESM imports only",
|
|
1741
1678
|
exports: ["replyToUser", "showObjects", "showAgentResponse"],
|
|
1742
1679
|
contains: "User-facing Harness response helpers for text, grounded object displays, and combined responses.",
|
|
1743
|
-
rule: "Import reply/display helpers from this module;
|
|
1680
|
+
rule: "Import reply/display helpers from this module; only the listed exports are available."
|
|
1744
1681
|
},
|
|
1745
1682
|
[HARNESS_V3_SESSION_MODULE]: {
|
|
1746
1683
|
importStyle: "named ESM imports only",
|
|
@@ -2018,9 +1955,9 @@ function splitDomainDocumentation(domainDocumentation) {
|
|
|
2018
1955
|
return { types: normalized, docs: "" };
|
|
2019
1956
|
}
|
|
2020
1957
|
var DOMAIN_HELPER_FUNCTION_NAMES = /* @__PURE__ */ new Set([
|
|
2021
|
-
"
|
|
2022
|
-
"
|
|
2023
|
-
"
|
|
1958
|
+
"replyToUser",
|
|
1959
|
+
"showAgentResponse",
|
|
1960
|
+
"showObjects"
|
|
2024
1961
|
]);
|
|
2025
1962
|
function inferGlobalActionToolsFromDomainTypes(domainTypes) {
|
|
2026
1963
|
const inferred = [];
|
|
@@ -2156,7 +2093,7 @@ function buildKnownFactsFromCheckpoint(checkpoint) {
|
|
|
2156
2093
|
return facts.slice(0, 8);
|
|
2157
2094
|
}
|
|
2158
2095
|
function buildGranularAgentSystemPrompt(input) {
|
|
2159
|
-
const outputMode = input.outputMode || "
|
|
2096
|
+
const outputMode = input.outputMode || "feed";
|
|
2160
2097
|
const promptCapabilities = resolvePromptCapabilities(input.capabilities);
|
|
2161
2098
|
const domainSections = splitDomainDocumentation(input.domainDocumentation);
|
|
2162
2099
|
const promptTools = resolvePromptTools(input.tools, domainSections.types);
|
|
@@ -2189,7 +2126,7 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
2189
2126
|
- For multi-record display, prefer a saved list/listName so the UI can render a table; use entryPaths for a few individual records.
|
|
2190
2127
|
- When the user asks to show, list, display, open, or "show them" for records you found, include those grounded records in \`show\`; do not answer only with a count or text summary.
|
|
2191
2128
|
- For count-only questions such as "how many", "how many X do I have", or "what is the total number of X", call the entity \`.count(...)\` or use page \`totalCount\` only when a page is already needed for other reasons. Answer with text only. Do not fetch, save, or display sample records just to ground a numeric count.
|
|
2192
|
-
- Use \`replyToUser(...)\`, \`showObjects(...)\`, or \`showAgentResponse(...)\` from \`@granular/agent\` when the host exposes job output helpers
|
|
2129
|
+
- Use \`replyToUser(...)\`, \`showObjects(...)\`, or \`showAgentResponse(...)\` from \`@granular/agent\` when the host exposes job output helpers.` : `- End every user-facing job by returning a short natural-language string.` : promptCapabilities.showRecords ? `- Every job that answers the user must emit \`replyToUser(...)\`, \`showObjects(...)\`, and/or \`showAgentResponse(...)\` from \`@granular/agent\`.
|
|
2193
2130
|
- \`replyToUser(...)\` displays text directly to the user in the host UI. Treat it as the user-facing progress and reply channel, not as a debug log.
|
|
2194
2131
|
- For long-running or multi-step jobs, send several short \`replyToUser(...)\` updates as useful milestones are reached so the user can see what is happening instead of waiting in silence.
|
|
2195
2132
|
- Write \`replyToUser(...)\` content in a friendly, readable product-assistant style: concrete, concise, and natural. Avoid robotic status dumps, raw implementation names, and unexplained IDs unless the ID helps the user.
|
|
@@ -2199,11 +2136,10 @@ function buildGranularAgentSystemPrompt(input) {
|
|
|
2199
2136
|
- Do not use \`showObjects({ entries: [...] })\` or \`showObjects({ saveAs, entries })\`. Save ordered pages, queues, search results, or ranked lists with \`groundedObjects.save(...)\`, then call \`showObjects({ variableNames: [...] })\` once.
|
|
2200
2137
|
- Use \`showAgentResponse({ reply, show: [record, action] })\` when one assistant message should combine text, grounded records, files, prepared actions, or action suggestions. The \`action\` can be a state handle such as \`record.lifecycle.approved\` or an action handle such as \`record.lifecycle.approved.reach()\`.
|
|
2201
2138
|
- Pass grounded records directly in \`show\` when the default record presentation answers the request. When the user asks for particular columns, comparisons, or computed values, import \`table\` (and \`relativeTime\` when useful) from \`@granular/agent\` and call \`showAgentResponse({ reply, show: table(records, [{ label: "Object", value: record => record.label }, { label: "When", value: record => relativeTime(record.timestamp) }]) })\`. Column callbacks must be synchronous and return a scalar, \`Date\`, or \`relativeTime(...)\`; they run inside the job and only resolved cells are persisted.
|
|
2202
|
-
- Do not use deprecated side-channel helpers such as \`agent_text_message(...)\`, \`agent_heap_objects(...)\`, or \`agent_message(...)\` unless the generated types expose no Harness v3 helper alternative.
|
|
2203
2139
|
- When the user asks to show, list, display, open, or "show them" for records you found, call \`showObjects(...)\`; do not answer only with a count or text summary.
|
|
2204
2140
|
- For count-only questions such as "how many", "how many X do I have", or "what is the total number of X", call the entity \`.count(...)\` or use page \`totalCount\` only when a page is already needed for other reasons. Answer with \`replyToUser(...)\` only. Do not call \`showObjects(...)\`, \`saveAs\`, or \`groundedObjects.save(...)\` unless the user also asked to see records or a later requested action needs a reusable record selection.
|
|
2205
2141
|
- Use stable saved list names that preserve identity and ordering so later references such as "the second item" or "back on the first slice" resolve to the correct earlier slice, not merely the most recent record.
|
|
2206
|
-
- Do not rely on the final return value for UI output. Do not return ad-hoc \`reply\` / \`show\` payloads instead of explicit
|
|
2142
|
+
- Do not rely on the final return value for UI output. Do not return ad-hoc \`reply\` / \`show\` payloads instead of explicit canonical feed calls.` : `- Every job that answers the user must emit \`replyToUser(...)\` from \`@granular/agent\`.
|
|
2207
2143
|
- \`replyToUser(...)\` displays text directly to the user in the host UI. Treat it as the user-facing progress and reply channel, not as a debug log.
|
|
2208
2144
|
- For long-running or multi-step jobs, send several short \`replyToUser(...)\` updates as useful milestones are reached so the user can see what is happening instead of waiting in silence.
|
|
2209
2145
|
- Write \`replyToUser(...)\` content in a friendly, readable product-assistant style: concrete, concise, and natural. Avoid robotic status dumps, raw implementation names, and unexplained IDs unless the ID helps the user.
|