@granular-software/sdk 0.4.25 → 0.4.27

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/index.js CHANGED
@@ -4610,6 +4610,22 @@ var Session = class {
4610
4610
  }
4611
4611
  };
4612
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
+ }
4613
4629
  // --- Public API ---
4614
4630
  get document() {
4615
4631
  return this.client.doc;
@@ -4760,6 +4776,20 @@ var Session = class {
4760
4776
  answer: resolvedAnswer,
4761
4777
  value: resolvedAnswer
4762
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);
4763
4793
  }
4764
4794
  /**
4765
4795
  * Get the current list of available effects.
@@ -4899,9 +4929,24 @@ var Session = class {
4899
4929
  * Get domain documentation for LLMs. Returns types (preferred) or fallback.
4900
4930
  */
4901
4931
  async getDomainDocumentation() {
4902
- const types = await this.getDomainTypes();
4903
- if (types && (types.includes("export declare class") || types.includes("export async function"))) {
4904
- return types;
4932
+ const [types, docs] = await Promise.all([
4933
+ this.getDomainTypes(),
4934
+ this.getDomainDocs()
4935
+ ]);
4936
+ const normalizedTypes = types.trim();
4937
+ const normalizedDocs = docs.trim();
4938
+ if (normalizedTypes && (normalizedTypes.includes("export declare class") || normalizedTypes.includes("export async function"))) {
4939
+ if (!normalizedDocs) {
4940
+ return normalizedTypes;
4941
+ }
4942
+ return [
4943
+ normalizedTypes,
4944
+ "Generated usage notes from ./sandbox-tools docs:",
4945
+ normalizedDocs
4946
+ ].join("\n\n");
4947
+ }
4948
+ if (normalizedDocs) {
4949
+ return normalizedDocs;
4905
4950
  }
4906
4951
  const summary = await this.getDomain();
4907
4952
  return this.generateFallbackDocs(summary);
@@ -9711,10 +9756,15 @@ external_exports.union([
9711
9756
  scalarType: external_exports.string().optional()
9712
9757
  }).strict()
9713
9758
  ]);
9759
+ external_exports.union([
9760
+ external_exports.boolean(),
9761
+ external_exports.object({
9762
+ enabled: external_exports.boolean().optional(),
9763
+ phonetic: external_exports.boolean().optional()
9764
+ }).strict()
9765
+ ]);
9714
9766
  external_exports.object({
9715
- operator: external_exports.enum(
9716
- [...VALIDATION_RULE_OPERATORS]
9717
- ),
9767
+ operator: external_exports.enum([...VALIDATION_RULE_OPERATORS]),
9718
9768
  stringValue: external_exports.string().optional(),
9719
9769
  numberValue: external_exports.number().optional(),
9720
9770
  booleanValue: external_exports.boolean().optional(),
@@ -9807,12 +9857,18 @@ function collectMetamodelSummarySelections(packages) {
9807
9857
  const propertyFields = [];
9808
9858
  const methodFields = [];
9809
9859
  for (const metamodelPackage of packages) {
9810
- pushUnique(classFields, metamodelPackage.summary.selections?.classFields || []);
9860
+ pushUnique(
9861
+ classFields,
9862
+ metamodelPackage.summary.selections?.classFields || []
9863
+ );
9811
9864
  pushUnique(
9812
9865
  propertyFields,
9813
9866
  metamodelPackage.summary.selections?.propertyFields || []
9814
9867
  );
9815
- pushUnique(methodFields, metamodelPackage.summary.selections?.methodFields || []);
9868
+ pushUnique(
9869
+ methodFields,
9870
+ metamodelPackage.summary.selections?.methodFields || []
9871
+ );
9816
9872
  }
9817
9873
  return {
9818
9874
  classFields: unique(classFields),
@@ -9900,7 +9956,11 @@ function createMetamodelRegistry(metamodelPackages) {
9900
9956
  return collectMetamodelSummarySelections(packages);
9901
9957
  },
9902
9958
  applyClassSummaryReaders(rawClass, classSummary) {
9903
- return applyMetamodelSummaryReadersToClass(packages, rawClass, classSummary);
9959
+ return applyMetamodelSummaryReadersToClass(
9960
+ packages,
9961
+ rawClass,
9962
+ classSummary
9963
+ );
9904
9964
  },
9905
9965
  applyPropertySummaryReaders(rawProperty, propertySummary) {
9906
9966
  return applyMetamodelSummaryReadersToProperty(
@@ -9910,7 +9970,11 @@ function createMetamodelRegistry(metamodelPackages) {
9910
9970
  );
9911
9971
  },
9912
9972
  applyMethodSummaryReaders(rawMethod, methodSummary) {
9913
- return applyMetamodelSummaryReadersToMethod(packages, rawMethod, methodSummary);
9973
+ return applyMetamodelSummaryReadersToMethod(
9974
+ packages,
9975
+ rawMethod,
9976
+ methodSummary
9977
+ );
9914
9978
  },
9915
9979
  applyClassIR(classIR, classSummary) {
9916
9980
  return applyMetamodelClassIR(packages, classIR, classSummary);
@@ -9958,6 +10022,10 @@ function mergeClassSummaryPatch(target, patch) {
9958
10022
  }
9959
10023
  function mergePropertySummaryPatch(target, patch) {
9960
10024
  pushUnique(target.notes, patch.notes || []);
10025
+ if (patch.searchable !== void 0) target.searchable = patch.searchable;
10026
+ if (patch.searchablePhonetic !== void 0) {
10027
+ target.searchablePhonetic = patch.searchablePhonetic;
10028
+ }
9961
10029
  if (patch.required !== void 0) target.required = patch.required;
9962
10030
  if (patch.enumRule !== void 0) target.enumRule = patch.enumRule;
9963
10031
  if (patch.filterBy !== void 0) target.filterBy = patch.filterBy;
@@ -9969,9 +10037,11 @@ function mergeMethodSummaryPatch(target, patch) {
9969
10037
  if (patch.effectKey !== void 0) target.effectKey = patch.effectKey;
9970
10038
  if (patch.description !== void 0) target.description = patch.description;
9971
10039
  if (patch.inputSchema !== void 0) target.inputSchema = patch.inputSchema;
9972
- if (patch.outputSchema !== void 0) target.outputSchema = patch.outputSchema;
10040
+ if (patch.outputSchema !== void 0)
10041
+ target.outputSchema = patch.outputSchema;
9973
10042
  if (patch.metamodels !== void 0) target.metamodels = patch.metamodels;
9974
- if (patch.effectBehaviors !== void 0) target.effectBehaviors = patch.effectBehaviors;
10043
+ if (patch.effectBehaviors !== void 0)
10044
+ target.effectBehaviors = patch.effectBehaviors;
9975
10045
  if (patch.static !== void 0) target.static = patch.static;
9976
10046
  }
9977
10047
  function toPascalCase(value) {
@@ -10477,12 +10547,20 @@ function defaultFilterOperators(scalarType) {
10477
10547
  switch ((scalarType || "").toLowerCase()) {
10478
10548
  case "number":
10479
10549
  case "date":
10480
- return ["equal_to", "greater_than", "less_than", "not_null"];
10550
+ return [
10551
+ "equal_to",
10552
+ "greater_than",
10553
+ "greater_than_or_equal_to",
10554
+ "less_than",
10555
+ "less_than_or_equal_to",
10556
+ "not_null"
10557
+ ];
10481
10558
  case "boolean":
10482
- return ["equal_to", "not_null"];
10559
+ return ["equal_to", "true", "false", "not_null"];
10483
10560
  default:
10484
10561
  return [
10485
10562
  "equal_to",
10563
+ "in",
10486
10564
  "contains",
10487
10565
  "not_contains",
10488
10566
  "starts_with",
@@ -10491,16 +10569,26 @@ function defaultFilterOperators(scalarType) {
10491
10569
  ];
10492
10570
  }
10493
10571
  }
10572
+ function supportsDefaultFilterBy(scalarType) {
10573
+ return ["string", "number", "boolean", "date"].includes(
10574
+ String(scalarType || "").toLowerCase()
10575
+ );
10576
+ }
10494
10577
  function normalizeFilterByInput(filterBy, scalarType) {
10495
- if (!filterBy) return null;
10578
+ if (filterBy === false) return null;
10579
+ if (filterBy === void 0) {
10580
+ if (!supportsDefaultFilterBy(scalarType)) return null;
10581
+ return { operators: defaultFilterOperators(scalarType), scalarType };
10582
+ }
10496
10583
  if (filterBy === true) {
10497
- return { operators: defaultFilterOperators(scalarType) };
10584
+ return { operators: defaultFilterOperators(scalarType), scalarType };
10498
10585
  }
10499
10586
  if (Array.isArray(filterBy)) {
10500
- return { operators: filterBy };
10587
+ return { operators: filterBy, scalarType };
10501
10588
  }
10502
10589
  return {
10503
- operators: filterBy.operators
10590
+ operators: filterBy.operators,
10591
+ scalarType: filterBy.scalarType || scalarType
10504
10592
  };
10505
10593
  }
10506
10594
  function buildFilterByFieldMutations(fieldPath, filterBy, scalarType) {
@@ -10511,7 +10599,7 @@ function buildFilterByFieldMutations(fieldPath, filterBy, scalarType) {
10511
10599
  label: `set filterBy on ${fieldPath}`,
10512
10600
  query: `mutation { at(path: ${JSON.stringify(fieldPath)}) { set_filter_by(operators: ${JSON.stringify(
10513
10601
  normalized.operators
10514
- )}) { operators } } }`
10602
+ )}${normalized.scalarType ? `, scalar_type: ${JSON.stringify(normalized.scalarType)}` : ""}) { operators } } }`
10515
10603
  }
10516
10604
  ];
10517
10605
  }
@@ -10521,7 +10609,7 @@ var filterByMetamodelPackage = defineMetamodelPackage({
10521
10609
  fieldRows: [
10522
10610
  {
10523
10611
  key: "filterBy",
10524
- description: "Exposes filter operators for generated query surfaces. Accepts `true`, an operator array, or `{ operators, scalarType }`."
10612
+ description: "Exposes filter operators for generated query surfaces. Scalar fields are filterable by default; set `filterBy: false` to opt out, or override with `true`, an operator array, or `{ operators, scalarType }`."
10525
10613
  }
10526
10614
  ]
10527
10615
  },
@@ -10785,6 +10873,123 @@ var requiredMetamodelPackage = defineMetamodelPackage({
10785
10873
  }
10786
10874
  });
10787
10875
 
10876
+ // ../metamodel-searchable/src/index.ts
10877
+ function supportsDefaultSearchable(scalarType) {
10878
+ return String(scalarType || "").toLowerCase() === "string";
10879
+ }
10880
+ function normalizeSearchableInput(searchable, scalarType) {
10881
+ if (!supportsDefaultSearchable(scalarType)) return null;
10882
+ if (typeof searchable === "boolean" || searchable === void 0) {
10883
+ return {
10884
+ enabled: searchable !== false,
10885
+ phonetic: false
10886
+ };
10887
+ }
10888
+ const enabled = searchable.enabled !== false;
10889
+ return {
10890
+ enabled,
10891
+ phonetic: enabled && searchable.phonetic === true
10892
+ };
10893
+ }
10894
+ function buildSearchableFieldMutations(fieldPath, searchable, scalarType) {
10895
+ const normalized = normalizeSearchableInput(searchable, scalarType);
10896
+ if (normalized === null) return [];
10897
+ return [
10898
+ {
10899
+ label: `set searchable on ${fieldPath}`,
10900
+ query: `mutation { at(path: ${JSON.stringify(fieldPath)}) { set_searchable(enabled: ${normalized.enabled}, phonetic: ${normalized.phonetic}) { enabled phonetic } } }`
10901
+ }
10902
+ ];
10903
+ }
10904
+ var searchableMetamodelPackage = defineMetamodelPackage({
10905
+ id: "searchable",
10906
+ docs: {
10907
+ fieldRows: [
10908
+ {
10909
+ key: "searchable",
10910
+ description: "Controls full-text search exposure for string fields. String fields are searchable by default; set `searchable: false` to opt out, or use `searchable: { phonetic: true }` to keep the field searchable while enabling FalkorDB phonetic matching for class-wide search."
10911
+ }
10912
+ ]
10913
+ },
10914
+ graphql: {
10915
+ typeDefs: [
10916
+ `
10917
+ type SearchableMetamodel {
10918
+ model: Model!
10919
+ enabled: Boolean!
10920
+ phonetic: Boolean!
10921
+ }
10922
+
10923
+ extend type Model {
10924
+ searchable: SearchableMetamodel
10925
+ }
10926
+
10927
+ extend type ModelMutation {
10928
+ set_searchable(enabled: Boolean!, phonetic: Boolean): SearchableMetamodel
10929
+ }
10930
+ `
10931
+ ],
10932
+ createResolvers({ run }) {
10933
+ return {
10934
+ SearchableMetamodel: {
10935
+ model: (value) => value.model,
10936
+ enabled: (value) => value.enabled !== false,
10937
+ phonetic: (value) => value.phonetic === true
10938
+ },
10939
+ Model: {
10940
+ searchable: async (ant) => await run(ant.searchable())
10941
+ },
10942
+ ModelMutation: {
10943
+ set_searchable: async (ant, { enabled, phonetic }) => {
10944
+ return {
10945
+ model: await run(ant.set_searchable(enabled, phonetic === true)),
10946
+ enabled,
10947
+ phonetic: phonetic === true
10948
+ };
10949
+ }
10950
+ }
10951
+ };
10952
+ }
10953
+ },
10954
+ manifest: {
10955
+ buildFieldMutations(fieldPath, spec) {
10956
+ return buildSearchableFieldMutations(
10957
+ fieldPath,
10958
+ spec.searchable,
10959
+ spec.type
10960
+ );
10961
+ }
10962
+ },
10963
+ summary: {
10964
+ selections: {
10965
+ propertyFields: [`searchable { enabled phonetic }`]
10966
+ },
10967
+ readPropertySummary(rawProperty) {
10968
+ if (typeof rawProperty.searchable?.enabled !== "boolean") {
10969
+ return {};
10970
+ }
10971
+ return {
10972
+ searchable: rawProperty.searchable.enabled,
10973
+ searchablePhonetic: rawProperty.searchable.phonetic === true
10974
+ };
10975
+ }
10976
+ },
10977
+ domain: {
10978
+ applyToPropertyIR(propertyIR, propertySummary) {
10979
+ if (String(propertySummary.type || "").toLowerCase() !== "string" || propertySummary.searchable === false) {
10980
+ return propertyIR;
10981
+ }
10982
+ return {
10983
+ ...propertyIR,
10984
+ docs: [
10985
+ ...propertyIR.docs,
10986
+ propertySummary.searchablePhonetic ? "Searchable via `search` using FalkorDB full-text query syntax with phonetic matching enabled." : "Searchable via `search` using FalkorDB full-text query syntax."
10987
+ ]
10988
+ };
10989
+ }
10990
+ }
10991
+ });
10992
+
10788
10993
  // ../metamodel-state-machine/src/index.ts
10789
10994
  function normalizeStateMachines(values) {
10790
10995
  return (values || []).map((machine) => {
@@ -11365,6 +11570,7 @@ var DEFAULT_METAMODEL_PACKAGES = [
11365
11570
  requiredMetamodelPackage,
11366
11571
  enumMetamodelPackage,
11367
11572
  filterByMetamodelPackage,
11573
+ searchableMetamodelPackage,
11368
11574
  validationRuleMetamodelPackage,
11369
11575
  stateMachineMetamodelPackage,
11370
11576
  effectBehaviorsMetamodelPackage
@@ -14784,6 +14990,306 @@ function resolveJobPresentation({
14784
14990
  };
14785
14991
  }
14786
14992
 
14993
+ // src/session-transcript.ts
14994
+ var EMPTY_HEAP = {
14995
+ entriesByPath: {},
14996
+ listsByName: {},
14997
+ variablesByName: {}};
14998
+ function asRecord4(value) {
14999
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
15000
+ return value;
15001
+ }
15002
+ function asArray2(value) {
15003
+ return Array.isArray(value) ? value : [];
15004
+ }
15005
+ function asNumber(value) {
15006
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
15007
+ }
15008
+ function asString(value) {
15009
+ return typeof value === "string" ? value : void 0;
15010
+ }
15011
+ function trimString(value) {
15012
+ return typeof value === "string" ? value.trim() : "";
15013
+ }
15014
+ function normalizeShowRefs(value) {
15015
+ const record = asRecord4(value);
15016
+ if (!record) return void 0;
15017
+ const normalizeRefs = (input) => {
15018
+ if (!Array.isArray(input)) return void 0;
15019
+ const refs = Array.from(
15020
+ new Set(
15021
+ input.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean)
15022
+ )
15023
+ );
15024
+ return refs.length > 0 ? refs : void 0;
15025
+ };
15026
+ const show = {
15027
+ entryPaths: normalizeRefs(record.entryPaths),
15028
+ listNames: normalizeRefs(record.listNames),
15029
+ variableNames: normalizeRefs(record.variableNames)
15030
+ };
15031
+ return show.entryPaths || show.listNames || show.variableNames ? show : void 0;
15032
+ }
15033
+ function stringifyTranscriptValue(value, fallback = "") {
15034
+ if (typeof value === "string") {
15035
+ return value.trim() || fallback;
15036
+ }
15037
+ if (typeof value === "boolean") {
15038
+ return value ? "Confirmed" : "Canceled";
15039
+ }
15040
+ if (value === void 0) {
15041
+ return fallback;
15042
+ }
15043
+ try {
15044
+ const json = JSON.stringify(value, null, 2);
15045
+ if (!json || json === "undefined") return fallback;
15046
+ return json.length > 2e3 ? `${json.slice(0, 2e3)}...` : json;
15047
+ } catch {
15048
+ return String(value);
15049
+ }
15050
+ }
15051
+ function buildArtifactHistory(show) {
15052
+ if (!show) return void 0;
15053
+ return `[Agent message]
15054
+ ${stringifyTranscriptValue({ show }, "")}`;
15055
+ }
15056
+ function normalizeConversationMessage(raw) {
15057
+ const record = asRecord4(raw);
15058
+ if (!record) return null;
15059
+ const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
15060
+ if (!role) return null;
15061
+ const content = trimString(
15062
+ record.content ?? record.reply ?? record.message ?? record.text
15063
+ );
15064
+ const show = normalizeShowRefs(record.show);
15065
+ const id = asString(record.id) || crypto.randomUUID();
15066
+ const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
15067
+ if (!content && !show) return null;
15068
+ return {
15069
+ id,
15070
+ role,
15071
+ content,
15072
+ timestamp,
15073
+ jobId: asString(record.jobId),
15074
+ promptId: asString(record.promptId),
15075
+ show,
15076
+ historyContent: role === "assistant" ? content ? `[Assistant reply]
15077
+ ${content}` : buildArtifactHistory(show) : void 0,
15078
+ source: "conversation"
15079
+ };
15080
+ }
15081
+ function normalizePromptEntries(jobId, rawPrompts, conversationPromptIds) {
15082
+ const promptsById = asRecord4(rawPrompts) || {};
15083
+ return Object.values(promptsById).map((value) => asRecord4(value)).filter((value) => Boolean(value)).sort(
15084
+ (left, right) => (asNumber(left.openedAt) || asNumber(left.answeredAt) || 0) - (asNumber(right.openedAt) || asNumber(right.answeredAt) || 0)
15085
+ ).flatMap((prompt) => {
15086
+ const promptId = asString(prompt.promptId);
15087
+ if (!promptId || conversationPromptIds.has(promptId)) return [];
15088
+ const title = trimString(prompt.title);
15089
+ const message = trimString(prompt.message);
15090
+ const assistantContent = message || title || "Input required";
15091
+ const openedAt = asNumber(prompt.openedAt) || 0;
15092
+ const answeredAt = asNumber(prompt.answeredAt) || openedAt;
15093
+ const entries = [
15094
+ {
15095
+ id: `prompt:${promptId}:assistant`,
15096
+ role: "assistant",
15097
+ content: assistantContent,
15098
+ timestamp: openedAt,
15099
+ jobId,
15100
+ promptId,
15101
+ historyContent: `[Assistant reply]
15102
+ ${assistantContent}`,
15103
+ source: "job_prompt"
15104
+ }
15105
+ ];
15106
+ if (Object.prototype.hasOwnProperty.call(prompt, "answer")) {
15107
+ entries.push({
15108
+ id: `prompt:${promptId}:user`,
15109
+ role: "user",
15110
+ content: stringifyTranscriptValue(prompt.answer, ""),
15111
+ timestamp: answeredAt,
15112
+ jobId,
15113
+ promptId,
15114
+ source: "job_prompt"
15115
+ });
15116
+ }
15117
+ return entries;
15118
+ });
15119
+ }
15120
+ function normalizeAgentMessageEntries(jobId, rawMessages) {
15121
+ return asArray2(rawMessages).map((value) => asRecord4(value)).filter((value) => Boolean(value)).sort(
15122
+ (left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
15123
+ ).flatMap((message) => {
15124
+ const messageId = asString(message.messageId) || asString(message.id) || crypto.randomUUID();
15125
+ const timestamp = asNumber(message.timestamp) || asNumber(message.ts) || 0;
15126
+ const reply = trimString(
15127
+ message.reply ?? message.message ?? message.text ?? message.content
15128
+ );
15129
+ const show = normalizeShowRefs(message.show);
15130
+ const entries = [];
15131
+ if (reply) {
15132
+ entries.push({
15133
+ id: `agent:${messageId}:text`,
15134
+ role: "assistant",
15135
+ content: reply,
15136
+ timestamp,
15137
+ jobId,
15138
+ historyContent: `[Assistant reply]
15139
+ ${reply}`,
15140
+ source: "job_agent_message"
15141
+ });
15142
+ }
15143
+ if (show) {
15144
+ entries.push({
15145
+ id: `agent:${messageId}:artifacts`,
15146
+ role: "assistant",
15147
+ content: "",
15148
+ timestamp,
15149
+ jobId,
15150
+ show,
15151
+ historyContent: buildArtifactHistory(show),
15152
+ source: "job_agent_message"
15153
+ });
15154
+ }
15155
+ return entries;
15156
+ });
15157
+ }
15158
+ function buildJobFallbackEntries(jobId, job, sessionHeap) {
15159
+ const timestamp = asNumber(job.finishedAt) || asNumber(job.startedAt) || asNumber(job.submittedAt) || 0;
15160
+ const resultPreview = stringifyTranscriptValue(
15161
+ job.result,
15162
+ "No job result recorded."
15163
+ );
15164
+ const presentation = resolveJobPresentation({
15165
+ jobId,
15166
+ result: job.result,
15167
+ stdout: [],
15168
+ sessionHeap
15169
+ });
15170
+ const entries = [];
15171
+ const responseText = presentation.responseText || "";
15172
+ if (responseText) {
15173
+ entries.push({
15174
+ id: `job:${jobId}:result-text`,
15175
+ role: "assistant",
15176
+ content: responseText,
15177
+ timestamp,
15178
+ jobId,
15179
+ historyContent: `[Assistant reply]
15180
+ ${responseText}`,
15181
+ source: "job_result"
15182
+ });
15183
+ }
15184
+ const show = {
15185
+ entryPaths: presentation.entries.map((entry) => entry.path),
15186
+ listNames: presentation.lists.map((list) => list.name)
15187
+ };
15188
+ if (show.entryPaths && show.entryPaths.length > 0 || show.listNames && show.listNames.length > 0) {
15189
+ entries.push({
15190
+ id: `job:${jobId}:result-artifacts`,
15191
+ role: "assistant",
15192
+ content: "",
15193
+ timestamp,
15194
+ jobId,
15195
+ show,
15196
+ historyContent: buildArtifactHistory(show),
15197
+ source: "job_result"
15198
+ });
15199
+ }
15200
+ if (entries.length === 0 && trimString(job.error)) {
15201
+ entries.push({
15202
+ id: `job:${jobId}:result-error`,
15203
+ role: "assistant",
15204
+ content: trimString(job.error),
15205
+ timestamp,
15206
+ jobId,
15207
+ historyContent: `[Assistant reply]
15208
+ ${trimString(job.error)}`,
15209
+ source: "job_result"
15210
+ });
15211
+ }
15212
+ if (entries.length === 0 && resultPreview && resultPreview !== "No job result recorded.") {
15213
+ entries.push({
15214
+ id: `job:${jobId}:result-preview`,
15215
+ role: "assistant",
15216
+ content: resultPreview,
15217
+ timestamp,
15218
+ jobId,
15219
+ historyContent: `[Assistant reply]
15220
+ ${resultPreview}`,
15221
+ source: "job_result"
15222
+ });
15223
+ }
15224
+ return entries;
15225
+ }
15226
+ function buildJobCodeEntry(jobId, job) {
15227
+ const code = trimString(job.source);
15228
+ if (!code) return null;
15229
+ const jobStatus = asString(job.status);
15230
+ const error = jobStatus === "failed" || jobStatus === "canceled" || jobStatus === "timeout" ? trimString(job.error) || `Job ${jobStatus}` : void 0;
15231
+ return {
15232
+ id: `job:${jobId}:code`,
15233
+ role: "assistant",
15234
+ content: "",
15235
+ timestamp: asNumber(job.submittedAt) || asNumber(job.startedAt) || asNumber(job.finishedAt) || 0,
15236
+ jobId,
15237
+ code,
15238
+ jobStatus,
15239
+ jobResultPreview: stringifyTranscriptValue(job.result, "No job result recorded."),
15240
+ error,
15241
+ source: "job_code"
15242
+ };
15243
+ }
15244
+ function buildSessionTranscript(input) {
15245
+ const liveDoc = input.liveDoc || null;
15246
+ const sessionHeap = input.sessionHeap || EMPTY_HEAP;
15247
+ const transcript = [];
15248
+ const conversationMessages = asArray2(asRecord4(liveDoc?.conversation)?.messages).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
15249
+ const conversationPromptIds = new Set(
15250
+ conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
15251
+ );
15252
+ const assistantConversationJobIds = new Set(
15253
+ conversationMessages.filter((message) => message.role === "assistant" && Boolean(message.jobId)).map((message) => message.jobId)
15254
+ );
15255
+ transcript.push(...conversationMessages);
15256
+ const jobsById = asRecord4(asRecord4(liveDoc?.jobs)?.byId) || {};
15257
+ const jobs = Object.values(jobsById).map((value) => asRecord4(value)).filter((value) => Boolean(value)).sort(
15258
+ (left, right) => (asNumber(left.submittedAt) || asNumber(left.startedAt) || asNumber(left.finishedAt) || 0) - (asNumber(right.submittedAt) || asNumber(right.startedAt) || asNumber(right.finishedAt) || 0)
15259
+ );
15260
+ for (const job of jobs) {
15261
+ const jobId = asString(job.jobId);
15262
+ if (!jobId) continue;
15263
+ const codeEntry = buildJobCodeEntry(jobId, job);
15264
+ if (codeEntry) {
15265
+ transcript.push(codeEntry);
15266
+ }
15267
+ transcript.push(
15268
+ ...normalizePromptEntries(jobId, job.prompts, conversationPromptIds)
15269
+ );
15270
+ if (!assistantConversationJobIds.has(jobId)) {
15271
+ const agentEntries = normalizeAgentMessageEntries(jobId, job.agentMessages);
15272
+ if (agentEntries.length > 0) {
15273
+ transcript.push(...agentEntries);
15274
+ } else {
15275
+ transcript.push(
15276
+ ...buildJobFallbackEntries(
15277
+ jobId,
15278
+ job,
15279
+ sessionHeap
15280
+ )
15281
+ );
15282
+ }
15283
+ }
15284
+ }
15285
+ return transcript.sort((left, right) => {
15286
+ if (left.timestamp !== right.timestamp) {
15287
+ return left.timestamp - right.timestamp;
15288
+ }
15289
+ return left.id.localeCompare(right.id);
15290
+ });
15291
+ }
15292
+
14787
15293
  exports.Environment = Environment;
14788
15294
  exports.Granular = Granular;
14789
15295
  exports.Session = Session;
@@ -14797,6 +15303,7 @@ exports.buildGranularAgentSessionBlock = buildGranularAgentSessionBlock;
14797
15303
  exports.buildGranularAgentSystemPrompt = buildGranularAgentSystemPrompt;
14798
15304
  exports.buildGranularAgentToolBlock = buildGranularAgentToolBlock;
14799
15305
  exports.buildGranularAgentWorkflowBlock = buildGranularAgentWorkflowBlock;
15306
+ exports.buildSessionTranscript = buildSessionTranscript;
14800
15307
  exports.createHarnessVerifierSnapshot = createHarnessVerifierSnapshot;
14801
15308
  exports.evaluateContinuation = evaluateContinuation;
14802
15309
  exports.extractPromptTokens = extractPromptTokens;