deepline 0.1.145 → 0.1.147

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.
@@ -38,6 +38,8 @@ import type {
38
38
  ToolResultTargetAccessor,
39
39
  ToolResultTargetMetadata,
40
40
  } from './tool-result-types';
41
+ import { createPlayDataset, type PlayDataset } from '../plays/dataset';
42
+ import { normalizeTableNamespace, sha256Hex } from '../plays/row-identity';
41
43
 
42
44
  type PathSegment = string | number | '*';
43
45
 
@@ -737,12 +739,22 @@ function resolveListRows(
737
739
  );
738
740
  let resolvedPath: string | null = null;
739
741
  let rows: Record<string, unknown>[] | null = null;
742
+ let emptyMatch: { path: string; rows: Record<string, unknown>[] } | null =
743
+ null;
740
744
  for (const candidate of candidates) {
741
745
  rows = normalizeRows(getAtPath(result, candidate));
742
- if (rows) {
746
+ if (!rows) {
747
+ continue;
748
+ }
749
+ if (rows.length > 0) {
743
750
  resolvedPath = candidate;
744
751
  break;
745
752
  }
753
+ emptyMatch ??= { path: candidate, rows };
754
+ }
755
+ if (!rows && emptyMatch) {
756
+ resolvedPath = emptyMatch.path;
757
+ rows = emptyMatch.rows;
746
758
  }
747
759
  if (!rows) continue;
748
760
  const storedPath = resolvedPath ?? path;
@@ -751,7 +763,12 @@ function resolveListRows(
751
763
  .filter(Boolean)
752
764
  .at(-1)
753
765
  ?.replace(/\[\d+\]$/, '');
754
- lists[name || storedPath] = { path: storedPath, rows };
766
+ const listName = name || storedPath;
767
+ const existing = lists[listName];
768
+ if (existing?.rows.length && rows.length === 0) {
769
+ continue;
770
+ }
771
+ lists[listName] = { path: storedPath, rows };
755
772
  }
756
773
  return lists;
757
774
  }
@@ -935,10 +952,26 @@ function buildExtractedAccessors(
935
952
  function buildListAccessors(
936
953
  resolved: Record<string, { path: string; rows: Record<string, unknown>[] }>,
937
954
  lists: Record<string, ToolResultListMetadata>,
955
+ toolId: string,
956
+ executionDiscriminator: string,
938
957
  ): Record<string, ToolResultListAccessor> {
939
958
  return Object.fromEntries(
940
959
  Object.entries(lists).map(([name, metadata]) => {
941
960
  const rows = resolved[name]?.rows ?? [];
961
+ const datasetDiscriminator = `${executionDiscriminator}:${listRowsFingerprint(rows)}`;
962
+ const dataset = createPlayDataset(rows, {
963
+ kind: 'csv',
964
+ sourceLabel: metadata.path,
965
+ tableNamespace: listTableNamespace(
966
+ toolId,
967
+ name,
968
+ metadata.path,
969
+ datasetDiscriminator,
970
+ ),
971
+ datasetId: `tool-list:${sha256Hex(
972
+ `${toolId}:${metadata.path}:${datasetDiscriminator}`,
973
+ )}`,
974
+ });
942
975
  const accessor = {
943
976
  path: metadata.path,
944
977
  count: metadata.count,
@@ -946,7 +979,7 @@ function buildListAccessors(
946
979
  } as ToolResultListAccessor;
947
980
  Object.defineProperty(accessor, 'get', {
948
981
  value() {
949
- return rows;
982
+ return dataset;
950
983
  },
951
984
  enumerable: false,
952
985
  });
@@ -955,6 +988,44 @@ function buildListAccessors(
955
988
  );
956
989
  }
957
990
 
991
+ function listRowsFingerprint(rows: readonly Record<string, unknown>[]): string {
992
+ try {
993
+ return sha256Hex(
994
+ JSON.stringify(
995
+ {
996
+ count: rows.length,
997
+ rows,
998
+ },
999
+ (_key, value) => (typeof value === 'bigint' ? value.toString() : value),
1000
+ ),
1001
+ ).slice(0, 12);
1002
+ } catch {
1003
+ return sha256Hex(String(rows.length)).slice(0, 12);
1004
+ }
1005
+ }
1006
+
1007
+ function listTableNamespace(
1008
+ toolId: string,
1009
+ name: string,
1010
+ path: string,
1011
+ discriminator: string,
1012
+ ): string {
1013
+ const raw = `${toolId}_${name || path || 'rows'}_${sha256Hex(discriminator).slice(0, 10)}`;
1014
+ try {
1015
+ return normalizeTableNamespace(raw);
1016
+ } catch {
1017
+ const hash = sha256Hex(raw).slice(0, 10);
1018
+ const leaf = name || path.split('.').filter(Boolean).at(-1) || 'rows';
1019
+ let prefix = 'rows';
1020
+ try {
1021
+ prefix = normalizeTableNamespace(leaf).slice(0, 52) || 'rows';
1022
+ } catch {
1023
+ prefix = 'rows';
1024
+ }
1025
+ return normalizeTableNamespace(`${prefix}_${hash}`);
1026
+ }
1027
+ }
1028
+
958
1029
  export function createToolExecuteResult<TResult = unknown>(input: {
959
1030
  status: string;
960
1031
  jobId?: string;
@@ -994,7 +1065,12 @@ export function createToolExecuteResult<TResult = unknown>(input: {
994
1065
  ...(result.meta ? { meta: result.meta } : {}),
995
1066
  };
996
1067
  const extractedValues = buildExtractedAccessors(targets);
997
- const extractedLists = buildListAccessors(resolvedLists, lists);
1068
+ const extractedLists = buildListAccessors(
1069
+ resolvedLists,
1070
+ lists,
1071
+ input.metadata.toolId,
1072
+ input.jobId ?? input.execution.cacheKey ?? 'inline',
1073
+ );
998
1074
  const wrapper = {
999
1075
  status: input.status,
1000
1076
  ...(input.jobId ? { job_id: input.jobId } : {}),
@@ -1063,7 +1139,7 @@ export function readValue(
1063
1139
  export function readList(
1064
1140
  result: ToolExecuteResult,
1065
1141
  selector?: readonly string[] | string,
1066
- ): Record<string, unknown>[] {
1142
+ ): PlayDataset<Record<string, unknown>> | Record<string, unknown>[] {
1067
1143
  if (selector) {
1068
1144
  const paths = Array.isArray(selector) ? selector : [selector];
1069
1145
  const found = findFirstTargetByPath(resultRootOf(result), paths)?.value;