@granular-software/sdk 0.4.45 → 0.4.47

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.
@@ -1556,7 +1556,8 @@ function buildGranularAgentSessionBlock(sessionContext) {
1556
1556
  runtimeId: sessionContext?.sandboxId || null,
1557
1557
  environmentId: sessionContext?.environmentId || null,
1558
1558
  userName: sessionContext?.userName || null,
1559
- domainRevision: sessionContext?.domainRevision || null
1559
+ domainRevision: sessionContext?.domainRevision || null,
1560
+ uiContext: sessionContext?.uiContext || null
1560
1561
  });
1561
1562
  }
1562
1563
  function buildGranularAgentHeapBlock(heapSummary) {
@@ -1803,7 +1804,7 @@ function buildGranularAgentToolBlock(tools, capabilityOverrides) {
1803
1804
  const rightScope = `${right.className || "global"}:${right.static ? "static" : "instance"}`;
1804
1805
  return leftScope.localeCompare(rightScope) || left.name.localeCompare(right.name);
1805
1806
  });
1806
- const writeActions = normalizedTools.filter((tool) => tool.ready !== false).map((tool) => {
1807
+ const availableActions = normalizedTools.filter((tool) => tool.ready !== false).map((tool) => {
1807
1808
  const scope = tool.className ? `${tool.static ? "class" : "record"}:${tool.className}` : "global";
1808
1809
  return {
1809
1810
  name: tool.name,
@@ -1814,7 +1815,8 @@ function buildGranularAgentToolBlock(tools, capabilityOverrides) {
1814
1815
  const capabilities = {
1815
1816
  executeCode: resolvedCapabilities.executeCode,
1816
1817
  readEntities: resolvedCapabilities.readEntities,
1817
- writeActions,
1818
+ availableActions,
1819
+ writeActions: availableActions,
1818
1820
  workflowHelpers: resolvedCapabilities.workflowHelpers,
1819
1821
  savedData: resolvedCapabilities.savedData,
1820
1822
  showRecords: resolvedCapabilities.showRecords
@@ -1828,7 +1830,7 @@ function buildGranularAgentActionIndex(tools) {
1828
1830
  return leftScope.localeCompare(rightScope) || left.name.localeCompare(right.name);
1829
1831
  });
1830
1832
  if (normalizedTools.length === 0) {
1831
- return "No domain write actions are available.";
1833
+ return "No executable actions are available.";
1832
1834
  }
1833
1835
  const globalTools = normalizedTools.filter((tool) => !tool.className);
1834
1836
  const staticTools = normalizedTools.filter(
@@ -1922,6 +1924,76 @@ function splitDomainDocumentation(domainDocumentation) {
1922
1924
  }
1923
1925
  return { types: normalized, docs: "" };
1924
1926
  }
1927
+ var DOMAIN_HELPER_FUNCTION_NAMES = /* @__PURE__ */ new Set([
1928
+ "agent_heap_objects",
1929
+ "agent_message",
1930
+ "agent_text_message"
1931
+ ]);
1932
+ function inferGlobalActionToolsFromDomainTypes(domainTypes) {
1933
+ const inferred = [];
1934
+ const seen = /* @__PURE__ */ new Set();
1935
+ const declarationPattern = /(?:export\s+)?declare\s+function\s+([A-Za-z_$][\w$]*)\s*\(/g;
1936
+ let match;
1937
+ while (match = declarationPattern.exec(domainTypes)) {
1938
+ const name = match[1];
1939
+ if (!name || DOMAIN_HELPER_FUNCTION_NAMES.has(name) || seen.has(name)) {
1940
+ continue;
1941
+ }
1942
+ seen.add(name);
1943
+ inferred.push({
1944
+ name,
1945
+ description: "Executable global action declared by the domain runtime."
1946
+ });
1947
+ }
1948
+ const actionLinePattern = /^-\s*([A-Za-z_$][\w$]*)\s+\(global\):\s*(.+)$/gm;
1949
+ while (match = actionLinePattern.exec(domainTypes)) {
1950
+ const name = match[1];
1951
+ if (!name || DOMAIN_HELPER_FUNCTION_NAMES.has(name) || seen.has(name)) {
1952
+ continue;
1953
+ }
1954
+ seen.add(name);
1955
+ inferred.push({
1956
+ name,
1957
+ description: match[2]?.trim() || "Executable global action declared by the domain runtime."
1958
+ });
1959
+ }
1960
+ const scopedActionLinePattern = /^-\s*([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)\s+\((record|class)\):\s*(.+)$/gm;
1961
+ while (match = scopedActionLinePattern.exec(domainTypes)) {
1962
+ const className = match[1]?.toLowerCase();
1963
+ const name = match[2];
1964
+ const scope = match[3];
1965
+ if (!className || !name || DOMAIN_HELPER_FUNCTION_NAMES.has(name)) {
1966
+ continue;
1967
+ }
1968
+ const key = `${className}:${scope}:${name}`;
1969
+ if (seen.has(key)) {
1970
+ continue;
1971
+ }
1972
+ seen.add(key);
1973
+ inferred.push({
1974
+ name,
1975
+ className,
1976
+ static: scope === "class",
1977
+ description: match[4]?.trim() || "Executable action declared by the domain runtime."
1978
+ });
1979
+ }
1980
+ return inferred;
1981
+ }
1982
+ function resolvePromptTools(tools, domainTypes) {
1983
+ const byKey = /* @__PURE__ */ new Map();
1984
+ for (const tool of tools || []) {
1985
+ if (!tool?.name) continue;
1986
+ const key = `${tool.className || "global"}:${tool.static ? "static" : "instance"}:${tool.name}`;
1987
+ byKey.set(key, tool);
1988
+ }
1989
+ for (const tool of inferGlobalActionToolsFromDomainTypes(domainTypes)) {
1990
+ const key = `global:instance:${tool.name}`;
1991
+ if (!byKey.has(key)) {
1992
+ byKey.set(key, tool);
1993
+ }
1994
+ }
1995
+ return [...byKey.values()];
1996
+ }
1925
1997
  function buildGranularAgentCheckpointBlock(checkpoint) {
1926
1998
  if (!checkpoint) {
1927
1999
  return renderConstBlock("previousCodeResult", null);
@@ -1994,12 +2066,13 @@ function buildGranularAgentSystemPrompt(input) {
1994
2066
  const outputMode = input.outputMode || "agentMessages";
1995
2067
  const promptCapabilities = resolvePromptCapabilities(input.capabilities);
1996
2068
  const domainSections = splitDomainDocumentation(input.domainDocumentation);
2069
+ const promptTools = resolvePromptTools(input.tools, domainSections.types);
1997
2070
  const sessionBlock = buildGranularAgentSessionBlock(input.sessionContext);
1998
2071
  const toolBlock = buildGranularAgentToolBlock(
1999
- input.tools,
2072
+ promptTools,
2000
2073
  input.capabilities
2001
2074
  );
2002
- const actionIndex = buildGranularAgentActionIndex(input.tools);
2075
+ const actionIndex = buildGranularAgentActionIndex(promptTools);
2003
2076
  const domainBlock = buildGranularAgentDomainBlock(domainSections.types);
2004
2077
  const workflowBlock = buildGranularAgentWorkflowBlock(input.workflowSummary);
2005
2078
  const checkpointBlock = buildGranularAgentCheckpointBlock(input.checkpoint);
@@ -2027,7 +2100,7 @@ function buildGranularAgentSystemPrompt(input) {
2027
2100
  - When \`agent_text_message(...)\` mentions a grounded record that should remain clickable/referable, wrap only the visible record label in a self-closing inline reference tag: \`<granular-object class="class_name" id="stable_id_or_path" label="Visible label" />\`. Use the actual class name and stable id/path from the runtime record or effect result; do not invent ids, field names, or snake/camel-case aliases that are not present in the type declarations or returned object.
2028
2101
  - Treat \`agent_heap_objects(...)\` as the UI display call for user-visible records, not as a general storage helper. Do not wrap records under an \`items\` key.
2029
2102
  - When records should remain reusable for follow-ups, first save the runtime record or ordered record array with \`await heap.setVar("stable_selection_name", value)\`, then display that saved selection exactly once with \`await agent_heap_objects({ variableNames: ["stable_selection_name"] })\`.
2030
- - \`heap.setVar(...)\` only accepts scalar values, runtime records/sandbox instances, or arrays of runtime records/sandbox instances. Do not save plain action/effect result objects. If an action returns an id/path for a created record that should remain referable, fetch the created record first, then save/display that fetched record.
2103
+ - \`heap.setVar(...)\` only accepts scalar values, runtime records/sandbox instances, or arrays of runtime records/sandbox instances from one class. Do not save plain action/effect result objects or arrays of JSON summaries returned by actions. If an action returns ids/paths for records that should remain referable or displayed as records, fetch the matching runtime records first with the generated class \`.get(...)\`/query API, then save/display those fetched records. If the action returned only structured summaries, answer from those summaries with \`agent_text_message(...)\`.
2031
2104
  - Do not use \`agent_heap_objects({ entries: [...] })\` or \`agent_heap_objects({ saveAs, entries })\` as a shortcut for ordered pages, queues, search results, or ranked lists; those forms can create duplicate or poorly labelled displays. Save the selection with \`heap.setVar(...)\` and display it via \`variableNames\` instead.
2032
2105
  - Use \`entryPaths\` only for a few already-known individual records and \`listNames\` only for a host-created list that you intentionally want to show. Do not display both an entry/list selection and a heap variable for the same records.
2033
2106
  - When the user asks to show, list, display, open, or "show them" for records you found, call \`agent_heap_objects(...)\`; do not answer only with a count or text summary.
@@ -2077,10 +2150,11 @@ ${outputRules}` : `Code:
2077
2150
  - Use choice only for 2 to 5 short grounded options.
2078
2151
  - For record choices, set each option value to a stable scalar such as the record \`_graphPath\` or \`id\`, not a label-only value.
2079
2152
  - After \`await loop.ask_user(...)\` returns from a choice prompt, tolerate either the option value, the option object, or a human-readable label by matching against value, id/path, label, and description before failing. If a returned label is a prefix or substring of exactly one option label, treat it as that option.
2080
- - Use \`loop.confirm(...)\` for yes/no confirmation only when the user explicitly asks for confirmation, action or permission metadata requires it, policy requires it, or material uncertainty remains after grounding.
2153
+ - Use \`loop.confirm(...)\` for yes/no confirmation only when the user explicitly asks for a separate confirmation step, policy requires confirmation outside the action runtime, or material uncertainty remains after grounding.
2154
+ - If action, effect, tool, or permission metadata already marks the invoked action as confirmation-gated, do not call \`loop.confirm(...)\` before invoking it. Ground the target and input, then call the action once; the runtime action policy will surface the confirmation prompt and resume the same invocation after approval.
2081
2155
  - Do not add a generic yes/no confirmation after the user has already made a grounded choice, unless one of those confirmation conditions still applies.
2082
- - Do not add confirmation only because an allowed mutation is visible to other people, customer-facing, or consequential. If the user clearly requested the mutation and the grounded target, action, and condition are unique, perform the mutation unless confirmation is required by the user, policy, action metadata, or remaining material uncertainty.
2083
- - A conditional request such as "if this is true, do that" is authorization to perform the requested action after you verify the condition. Once the condition, target, and action are grounded uniquely, call the action directly; do not ask "should I perform/post/send this?" unless the user, policy, action metadata, or unresolved material uncertainty requires confirmation. The visibility or impact of an allowed action is not by itself unresolved uncertainty.
2156
+ - Do not add confirmation only because an allowed mutation is visible to other people, customer-facing, or consequential. If the user clearly requested the mutation and the grounded target, action, and condition are unique, perform the mutation unless confirmation is required outside the action runtime or remaining material uncertainty exists.
2157
+ - A conditional request such as "if this is true, do that" is authorization to perform the requested action after you verify the condition. Once the condition, target, and action are grounded uniquely, call the action directly; do not ask "should I perform/post/send this?" unless the user, policy outside the action runtime, or unresolved material uncertainty requires confirmation. The visibility or impact of an allowed action is not by itself unresolved uncertainty.
2084
2158
  - If the user explicitly asks you to stop for confirmation, natural-language text such as "please confirm" is not enough: call \`await loop.confirm(...)\` before the mutation, then perform the approved mutation in the same resumed job when it returns true.
2085
2159
  - Reuse existing task, decision, and closure ids from [State].
2086
2160
  - If a user request matches both a domain record/action and a workflow helper, prefer the domain capability.` : "";
@@ -2226,7 +2300,8 @@ Query policy:
2226
2300
  - For operational blocker, risk, status, or "what is happening" questions, inspect the relevant record's scalar fields such as status, priority, blocker, summary, latest update/message, due date, amount, and other domain-specific descriptive fields before answering.
2227
2301
  - For read-only readiness, risk, health, or status summaries, call any visible read-only assessment/status action on the grounded primary record before ad-hoc aggregation when such an action semantically matches the request. Use the returned fields in the reply and supplement with counts or record reads only when useful.
2228
2302
  - Do not hide required visible read-only assessment/status actions inside broad try/catch blocks. The runtime action surface should show that the assessment action ran.
2229
- - Treat action/effect results as structured values, not necessarily arrays. Before indexing, iterating, checking \`.length\`, or calling array methods, normalize the result first: use the result itself only when \`Array.isArray(result)\`; otherwise read the exact array field shown in the output schema, or a documented array field such as \`items\`, \`matches\`, \`results\`, \`records\`, \`entries\`, \`candidates\`, \`options\`, or a domain-specific array field. Never convert a non-array object result to \`[]\` before checking its documented fields.
2303
+ - Treat action/effect results as structured values, not necessarily arrays. Before indexing, iterating, checking \`.length\`, or calling array methods, normalize the result first: use the result itself only when \`Array.isArray(result)\`; otherwise read the exact array field shown in the output schema, or a documented array field such as \`items\`, \`matches\`, \`results\`, \`records\`, \`entries\`, \`candidates\`, \`options\`, \`requests\`, \`vendors\`, \`transactions\`, \`approvals\`, \`receipts\`, or another domain-specific array field. If a structured result has \`count > 0\`, never conclude there are no matches until you inspect every array-valued field on that result object, especially fields named by the output schema. Never convert a non-array object result to \`[]\` before checking its documented fields.
2304
+ - Plain JSON objects returned by actions are not sandbox record instances, even when they contain ids, titles, labels, or status fields. Use them for reasoning and text responses. Do not pass action-returned JSON objects or arrays directly to \`heap.setVar(...)\` or \`agent_heap_objects(...)\`; fetch corresponding runtime records first when the user needs record display or follow-up references.
2230
2305
  - When a visible search, lookup, availability, or assessment action returns candidates or matches, treat those returned records as already scoped by the action inputs unless the output schema gives reliable fields for further narrowing. When matching returned candidates to grounded records, use the output schema's actual identifier fields, including \`id\`, \`path\`, or fields ending in \`Id\`; do not assume candidates have \`_graphPath\`. Do not discard all returned candidates by re-filtering on guessed property names.
2231
2306
  - For scheduling actions, convert relative wording into concrete ISO timestamps before mutating records.
2232
2307
  - When a decision depends on fresh external state and a visible read-only status/lookup action exists on the grounded record, call it before deciding, mutating, or refusing based on stale stored fields.
@@ -2288,6 +2363,7 @@ ${domainSections.docs}
2288
2363
 
2289
2364
  Actions:
2290
2365
  ${actionIndex}
2366
+ - Global actions are executable functions exported by "./sandbox-tools"; import each global action you call, e.g. \`import { some_action } from "./sandbox-tools"; await some_action(...)\`. This includes frontend actions such as opening, focusing, or navigating the host UI.
2291
2367
  - Actions listed under "Record-level" are instance methods. First fetch or find the specific record, then call the action on that instance, e.g. \`const item = await Item.get({ path }); await item.action_name(...)\`.
2292
2368
  - Actions listed under "Class-level" are class/static methods. Call them on the imported class, e.g. \`await Item.action_name(...)\`.
2293
2369
  - The action index is the visibility contract. If an action is listed for a class, call it directly on fetched/listed instances of that class; do not use \`typeof record.action_name === "function"\` as a discovery gate. If an action is not listed, do not call it.