@ekairos/structure 1.21.53-beta.0 → 1.21.56-beta.0

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.
Files changed (83) hide show
  1. package/dist/clearDataset.tool.d.ts +0 -1
  2. package/dist/clearDataset.tool.js +0 -1
  3. package/dist/completeObject.tool.d.ts +0 -1
  4. package/dist/completeObject.tool.js +0 -1
  5. package/dist/completeRows.tool.d.ts +0 -1
  6. package/dist/completeRows.tool.js +0 -1
  7. package/dist/dataset/steps.d.ts +0 -1
  8. package/dist/dataset/steps.js +39 -3
  9. package/dist/datasetFiles.d.ts +0 -1
  10. package/dist/datasetFiles.js +0 -1
  11. package/dist/datasetReader.d.ts +16 -0
  12. package/dist/datasetReader.js +25 -0
  13. package/dist/domain.d.ts +0 -1
  14. package/dist/domain.js +0 -1
  15. package/dist/executeCommand.tool.d.ts +0 -1
  16. package/dist/executeCommand.tool.js +0 -1
  17. package/dist/file/steps.d.ts +0 -1
  18. package/dist/file/steps.js +2 -3
  19. package/dist/generateSchema.tool.d.ts +0 -1
  20. package/dist/generateSchema.tool.js +0 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +1 -1
  23. package/dist/prompts.d.ts +0 -1
  24. package/dist/prompts.js +0 -1
  25. package/dist/rowsOutputPaging.d.ts +57 -0
  26. package/dist/rowsOutputPaging.js +148 -0
  27. package/dist/rowsOutputPaging.steps.d.ts +37 -0
  28. package/dist/rowsOutputPaging.steps.js +125 -0
  29. package/dist/rowsPagination.steps.d.ts +59 -0
  30. package/dist/rowsPagination.steps.js +190 -0
  31. package/dist/runtime.d.ts +9 -0
  32. package/dist/runtime.js +12 -0
  33. package/dist/sandbox/steps.d.ts +0 -1
  34. package/dist/sandbox/steps.js +5 -2
  35. package/dist/schema.d.ts +0 -1
  36. package/dist/schema.js +3 -2
  37. package/dist/service.d.ts +0 -1
  38. package/dist/service.js +43 -34
  39. package/dist/steps/commitFromEvents.step.d.ts +0 -1
  40. package/dist/steps/commitFromEvents.step.js +1 -2
  41. package/dist/steps/persistObjectFromStory.step.d.ts +0 -1
  42. package/dist/steps/persistObjectFromStory.step.js +2 -3
  43. package/dist/structure.d.ts +29 -4
  44. package/dist/structure.js +35 -5
  45. package/package.json +14 -4
  46. package/dist/clearDataset.tool.d.ts.map +0 -1
  47. package/dist/clearDataset.tool.js.map +0 -1
  48. package/dist/completeObject.tool.d.ts.map +0 -1
  49. package/dist/completeObject.tool.js.map +0 -1
  50. package/dist/completeRows.tool.d.ts.map +0 -1
  51. package/dist/completeRows.tool.js.map +0 -1
  52. package/dist/dataset/steps.d.ts.map +0 -1
  53. package/dist/dataset/steps.js.map +0 -1
  54. package/dist/datasetFiles.d.ts.map +0 -1
  55. package/dist/datasetFiles.js.map +0 -1
  56. package/dist/domain.d.ts.map +0 -1
  57. package/dist/domain.js.map +0 -1
  58. package/dist/executeCommand.tool.d.ts.map +0 -1
  59. package/dist/executeCommand.tool.js.map +0 -1
  60. package/dist/file/steps.d.ts.map +0 -1
  61. package/dist/file/steps.js.map +0 -1
  62. package/dist/generateSchema.tool.d.ts.map +0 -1
  63. package/dist/generateSchema.tool.js.map +0 -1
  64. package/dist/index.d.ts.map +0 -1
  65. package/dist/index.js.map +0 -1
  66. package/dist/prompts.d.ts.map +0 -1
  67. package/dist/prompts.js.map +0 -1
  68. package/dist/sandbox/steps.d.ts.map +0 -1
  69. package/dist/sandbox/steps.js.map +0 -1
  70. package/dist/schema.d.ts.map +0 -1
  71. package/dist/schema.js.map +0 -1
  72. package/dist/service.d.ts.map +0 -1
  73. package/dist/service.js.map +0 -1
  74. package/dist/steps/commitFromEvents.step.d.ts.map +0 -1
  75. package/dist/steps/commitFromEvents.step.js.map +0 -1
  76. package/dist/steps/persistObjectFromStory.step.d.ts.map +0 -1
  77. package/dist/steps/persistObjectFromStory.step.js.map +0 -1
  78. package/dist/structure.d.ts.map +0 -1
  79. package/dist/structure.js.map +0 -1
  80. package/dist/types/runtime.d.ts +0 -56
  81. package/dist/types/runtime.d.ts.map +0 -1
  82. package/dist/types/runtime.js +0 -2
  83. package/dist/types/runtime.js.map +0 -1
@@ -0,0 +1,59 @@
1
+ import { type DatasetSandboxId } from "./sandbox/steps";
2
+ /**
3
+ * Step 1: Download Structure rows output file (output.jsonl) into a sandbox.
4
+ *
5
+ * This enables pagination by reading chunks from the local sandbox filesystem.
6
+ */
7
+ export declare function downloadStructureRowsOutputToSandboxStep(params: {
8
+ env: any;
9
+ sandboxId: DatasetSandboxId;
10
+ structureId: string;
11
+ }): Promise<{
12
+ filePath: string;
13
+ }>;
14
+ /**
15
+ * @deprecated Prefer `downloadStructureRowsOutputToSandboxStep` (kept for symmetry with chunk naming).
16
+ *
17
+ * Note: The name includes `RowsOutputJsonl` to be explicit about the file format.
18
+ */
19
+ export declare function structureDownloadRowsOutputJsonlToSandboxStep(params: {
20
+ env: any;
21
+ sandboxId: DatasetSandboxId;
22
+ structureId: string;
23
+ }): Promise<{
24
+ filePath: string;
25
+ }>;
26
+ /**
27
+ * Step 2: Read a chunk/page of JSONL records from the downloaded sandbox file.
28
+ *
29
+ * Naming (consistent):
30
+ * - `structureReadRowsOutputJsonlStep` reads the whole file (base64)
31
+ * - `structureReadRowsOutputJsonlChunkStep` reads a paginated chunk from sandbox
32
+ *
33
+ * Offset/limit are line-based (0-indexed).
34
+ */
35
+ export declare function structureReadRowsOutputJsonlChunkStep(params: {
36
+ env: any;
37
+ sandboxId: DatasetSandboxId;
38
+ structureId: string;
39
+ offset: number;
40
+ limit: number;
41
+ }): Promise<{
42
+ records: any[];
43
+ nextOffset: number;
44
+ done: boolean;
45
+ }>;
46
+ /**
47
+ * @deprecated Use `structureReadRowsOutputJsonlChunkStep` instead (naming consistency).
48
+ */
49
+ export declare function readStructureRowsChunkFromSandboxStep(params: {
50
+ env: any;
51
+ sandboxId: DatasetSandboxId;
52
+ structureId: string;
53
+ offset: number;
54
+ limit: number;
55
+ }): Promise<{
56
+ records: any[];
57
+ nextOffset: number;
58
+ done: boolean;
59
+ }>;
@@ -0,0 +1,190 @@
1
+ import { getDatasetWorkstation } from "./datasetFiles";
2
+ import { runDatasetSandboxCommandStep, writeDatasetSandboxTextFileStep, } from "./sandbox/steps";
3
+ async function getRowsOutputUrl(params) {
4
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
5
+ const runtime = (await resolveStoryRuntime(params.env));
6
+ const db = runtime.db;
7
+ const contextKey = `structure:${params.structureId}`;
8
+ const query = (await db.query({
9
+ context_contexts: {
10
+ $: { where: { key: contextKey }, limit: 1 },
11
+ structure_output_file: {},
12
+ },
13
+ }));
14
+ const ctx = query.context_contexts?.[0];
15
+ const linked = Array.isArray(ctx?.structure_output_file) ? ctx.structure_output_file[0] : ctx?.structure_output_file;
16
+ const url = linked?.url;
17
+ if (!url) {
18
+ throw new Error("Rows output file not found");
19
+ }
20
+ return String(url);
21
+ }
22
+ /**
23
+ * Step 1: Download Structure rows output file (output.jsonl) into a sandbox.
24
+ *
25
+ * This enables pagination by reading chunks from the local sandbox filesystem.
26
+ */
27
+ export async function downloadStructureRowsOutputToSandboxStep(params) {
28
+ "use step";
29
+ const workstation = getDatasetWorkstation(params.structureId);
30
+ const filePath = `${workstation}/rows_output.jsonl`;
31
+ const scriptPath = `${workstation}/download_rows_output.py`;
32
+ // Ensure directory exists
33
+ await runDatasetSandboxCommandStep({
34
+ env: params.env,
35
+ sandboxId: params.sandboxId,
36
+ cmd: "mkdir",
37
+ args: ["-p", workstation],
38
+ });
39
+ const url = await getRowsOutputUrl({ env: params.env, structureId: params.structureId });
40
+ // Write a deterministic script to the sandbox and run it (no external deps).
41
+ await writeDatasetSandboxTextFileStep({
42
+ env: params.env,
43
+ sandboxId: params.sandboxId,
44
+ path: scriptPath,
45
+ text: [
46
+ "import argparse",
47
+ "import urllib.request",
48
+ "",
49
+ "def main():",
50
+ " p = argparse.ArgumentParser()",
51
+ " p.add_argument('--url', required=True)",
52
+ " p.add_argument('--out', required=True)",
53
+ " args = p.parse_args()",
54
+ "",
55
+ " # Download to local sandbox file",
56
+ " with urllib.request.urlopen(args.url, timeout=60) as r:",
57
+ " data = r.read()",
58
+ " with open(args.out, 'wb') as f:",
59
+ " f.write(data)",
60
+ "",
61
+ " print('ok')",
62
+ " print('bytes', len(data))",
63
+ "",
64
+ "if __name__ == '__main__':",
65
+ " main()",
66
+ "",
67
+ ].join("\n"),
68
+ });
69
+ const res = await runDatasetSandboxCommandStep({
70
+ env: params.env,
71
+ sandboxId: params.sandboxId,
72
+ cmd: "python",
73
+ args: [scriptPath, "--url", url, "--out", filePath],
74
+ });
75
+ if (res.exitCode !== 0) {
76
+ throw new Error(res.stderr || "Failed to download rows output into sandbox");
77
+ }
78
+ return { filePath };
79
+ }
80
+ /**
81
+ * @deprecated Prefer `downloadStructureRowsOutputToSandboxStep` (kept for symmetry with chunk naming).
82
+ *
83
+ * Note: The name includes `RowsOutputJsonl` to be explicit about the file format.
84
+ */
85
+ export async function structureDownloadRowsOutputJsonlToSandboxStep(params) {
86
+ "use step";
87
+ return await downloadStructureRowsOutputToSandboxStep(params);
88
+ }
89
+ /**
90
+ * Step 2: Read a chunk/page of JSONL records from the downloaded sandbox file.
91
+ *
92
+ * Naming (consistent):
93
+ * - `structureReadRowsOutputJsonlStep` reads the whole file (base64)
94
+ * - `structureReadRowsOutputJsonlChunkStep` reads a paginated chunk from sandbox
95
+ *
96
+ * Offset/limit are line-based (0-indexed).
97
+ */
98
+ export async function structureReadRowsOutputJsonlChunkStep(params) {
99
+ "use step";
100
+ const workstation = getDatasetWorkstation(params.structureId);
101
+ const filePath = `${workstation}/rows_output.jsonl`;
102
+ const scriptPath = `${workstation}/read_rows_chunk.py`;
103
+ await writeDatasetSandboxTextFileStep({
104
+ env: params.env,
105
+ sandboxId: params.sandboxId,
106
+ path: scriptPath,
107
+ text: [
108
+ "import argparse",
109
+ "import json",
110
+ "",
111
+ "def main():",
112
+ " p = argparse.ArgumentParser()",
113
+ " p.add_argument('--path', required=True)",
114
+ " p.add_argument('--offset', type=int, required=True)",
115
+ " p.add_argument('--limit', type=int, required=True)",
116
+ " args = p.parse_args()",
117
+ "",
118
+ " records = []",
119
+ " current = 0",
120
+ " taken = 0",
121
+ " done = True",
122
+ "",
123
+ " with open(args.path, 'r', encoding='utf-8', errors='replace') as f:",
124
+ " for line in f:",
125
+ " if current < args.offset:",
126
+ " current += 1",
127
+ " continue",
128
+ " if taken >= args.limit:",
129
+ " done = False",
130
+ " break",
131
+ " line = line.strip()",
132
+ " if not line:",
133
+ " current += 1",
134
+ " continue",
135
+ " try:",
136
+ " records.append(json.loads(line))",
137
+ " except Exception:",
138
+ " # Skip invalid JSON line",
139
+ " pass",
140
+ " taken += 1",
141
+ " current += 1",
142
+ "",
143
+ " out = {",
144
+ " 'records': records,",
145
+ " 'nextOffset': args.offset + taken,",
146
+ " 'done': done,",
147
+ " }",
148
+ " print(json.dumps(out, ensure_ascii=False))",
149
+ "",
150
+ "if __name__ == '__main__':",
151
+ " main()",
152
+ "",
153
+ ].join("\n"),
154
+ });
155
+ const res = await runDatasetSandboxCommandStep({
156
+ env: params.env,
157
+ sandboxId: params.sandboxId,
158
+ cmd: "python",
159
+ args: [
160
+ scriptPath,
161
+ "--path",
162
+ filePath,
163
+ "--offset",
164
+ String(Math.max(0, params.offset ?? 0)),
165
+ "--limit",
166
+ String(Math.max(1, params.limit ?? 1)),
167
+ ],
168
+ });
169
+ if (res.exitCode !== 0) {
170
+ throw new Error(res.stderr || "Failed to read rows chunk from sandbox");
171
+ }
172
+ const text = (res.stdout ?? "").trim();
173
+ if (!text) {
174
+ return { records: [], nextOffset: params.offset, done: true };
175
+ }
176
+ // The script prints a single JSON object.
177
+ const parsed = JSON.parse(text);
178
+ return {
179
+ records: Array.isArray(parsed?.records) ? parsed.records : [],
180
+ nextOffset: Number(parsed?.nextOffset ?? params.offset),
181
+ done: Boolean(parsed?.done),
182
+ };
183
+ }
184
+ /**
185
+ * @deprecated Use `structureReadRowsOutputJsonlChunkStep` instead (naming consistency).
186
+ */
187
+ export async function readStructureRowsChunkFromSandboxStep(params) {
188
+ "use step";
189
+ return await structureReadRowsOutputJsonlChunkStep(params);
190
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Internal helper to resolve Story runtime from within workflow steps.
3
+ *
4
+ * Why dynamic import?
5
+ * - Some bundlers (notably Turbopack step bundles) can drop/hoist static imports in "use-step" modules,
6
+ * causing `ReferenceError: resolveStoryRuntime is not defined`.
7
+ * - Using a dynamic import keeps the symbol resolution local to the step runtime.
8
+ */
9
+ export declare function getStoryRuntime(env: any): Promise<import("@ekairos/story/runtime").StoryRuntime>;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Internal helper to resolve Story runtime from within workflow steps.
3
+ *
4
+ * Why dynamic import?
5
+ * - Some bundlers (notably Turbopack step bundles) can drop/hoist static imports in "use-step" modules,
6
+ * causing `ReferenceError: resolveStoryRuntime is not defined`.
7
+ * - Using a dynamic import keeps the symbol resolution local to the step runtime.
8
+ */
9
+ export async function getStoryRuntime(env) {
10
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
11
+ return await resolveStoryRuntime(env);
12
+ }
@@ -71,4 +71,3 @@ export declare function stopDatasetSandboxStep(params: {
71
71
  env: any;
72
72
  sandboxId: DatasetSandboxId;
73
73
  }): Promise<void>;
74
- //# sourceMappingURL=steps.d.ts.map
@@ -1,8 +1,8 @@
1
- import { resolveStoryRuntime } from "@ekairos/story/runtime";
2
1
  export async function createDatasetSandboxStep(params) {
3
2
  "use step";
4
3
  console.log("[ekairos/structure] sandbox.step createSandbox begin");
5
4
  console.log("[ekairos/structure] sandbox.step createSandbox runtime", params.runtime);
5
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
6
6
  const db = (await resolveStoryRuntime(params.env)).db;
7
7
  const { SandboxService } = (await import("@ekairos/sandbox"));
8
8
  const service = new SandboxService(db);
@@ -18,6 +18,7 @@ export async function runDatasetSandboxCommandStep(params) {
18
18
  console.log("[ekairos/structure] sandbox.step runCommand begin");
19
19
  console.log("[ekairos/structure] sandbox.step runCommand sandboxId", params.sandboxId);
20
20
  console.log("[ekairos/structure] sandbox.step runCommand cmd", params.cmd);
21
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
21
22
  const db = (await resolveStoryRuntime(params.env)).db;
22
23
  const { SandboxService } = (await import("@ekairos/sandbox"));
23
24
  const service = new SandboxService(db);
@@ -38,6 +39,7 @@ export async function writeDatasetSandboxFilesStep(params) {
38
39
  console.log("[ekairos/structure] sandbox.step writeFiles begin");
39
40
  console.log("[ekairos/structure] sandbox.step writeFiles sandboxId", params.sandboxId);
40
41
  console.log("[ekairos/structure] sandbox.step writeFiles paths", params.files.map((f) => f.path));
42
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
41
43
  const db = (await resolveStoryRuntime(params.env)).db;
42
44
  const { SandboxService } = (await import("@ekairos/sandbox"));
43
45
  const service = new SandboxService(db);
@@ -67,6 +69,7 @@ export async function readDatasetSandboxFileStep(params) {
67
69
  console.log("[ekairos/structure] sandbox.step readFile begin");
68
70
  console.log("[ekairos/structure] sandbox.step readFile sandboxId", params.sandboxId);
69
71
  console.log("[ekairos/structure] sandbox.step readFile path", params.path);
72
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
70
73
  const db = (await resolveStoryRuntime(params.env)).db;
71
74
  const { SandboxService } = (await import("@ekairos/sandbox"));
72
75
  const service = new SandboxService(db);
@@ -93,6 +96,7 @@ export async function stopDatasetSandboxStep(params) {
93
96
  "use step";
94
97
  console.log("[ekairos/structure] sandbox.step stopSandbox begin");
95
98
  console.log("[ekairos/structure] sandbox.step stopSandbox sandboxId", params.sandboxId);
99
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
96
100
  const db = (await resolveStoryRuntime(params.env)).db;
97
101
  const { SandboxService } = (await import("@ekairos/sandbox"));
98
102
  const service = new SandboxService(db);
@@ -101,4 +105,3 @@ export async function stopDatasetSandboxStep(params) {
101
105
  throw new Error(result.error);
102
106
  console.log("[ekairos/structure] sandbox.step stopSandbox ok");
103
107
  }
104
- //# sourceMappingURL=steps.js.map
package/dist/schema.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export declare const structureDomain: any;
2
- //# sourceMappingURL=schema.d.ts.map
package/dist/schema.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { i } from "@instantdb/core";
2
2
  import { domain } from "@ekairos/domain";
3
- import { storyDomain } from "@ekairos/story";
3
+ import { storyDomain } from "@ekairos/story/schema";
4
+ import { sandboxDomain } from "@ekairos/sandbox/schema";
4
5
  const entities = {
5
6
  // Keep $files compatible with Instant's base file fields used by structure flows.
6
7
  $files: i.entity({
@@ -29,5 +30,5 @@ const links = {
29
30
  const rooms = {};
30
31
  export const structureDomain = domain("structure")
31
32
  .includes(storyDomain)
33
+ .includes(sandboxDomain)
32
34
  .schema({ entities, links, rooms });
33
- //# sourceMappingURL=schema.js.map
package/dist/service.d.ts CHANGED
@@ -38,4 +38,3 @@ export declare class DatasetService {
38
38
  fileId: string;
39
39
  }): Promise<ServiceResult<void>>;
40
40
  }
41
- //# sourceMappingURL=service.d.ts.map
package/dist/service.js CHANGED
@@ -55,42 +55,22 @@ export class DatasetService {
55
55
  if (!url)
56
56
  return { ok: false, error: "Rows output file not found" };
57
57
  async function* createGenerator(fileUrl) {
58
- const response = await fetch(fileUrl);
59
- if (!response.ok || !response.body) {
60
- throw new Error("Failed to download rows output file");
61
- }
62
- const reader = response.body.getReader();
63
- const decoder = new TextDecoder("utf-8");
64
- let buffer = "";
65
- while (true) {
66
- const { value, done } = await reader.read();
67
- if (done)
68
- break;
69
- buffer += decoder.decode(value, { stream: true });
70
- let newlineIndex = buffer.indexOf("\n");
71
- while (newlineIndex !== -1) {
72
- const line = buffer.slice(0, newlineIndex);
73
- buffer = buffer.slice(newlineIndex + 1);
74
- const trimmed = line.trim();
75
- if (trimmed) {
76
- try {
77
- const record = JSON.parse(trimmed);
78
- yield record;
79
- }
80
- catch {
81
- // skip invalid
82
- }
83
- }
84
- newlineIndex = buffer.indexOf("\n");
85
- }
86
- }
87
- const remaining = buffer.trim();
88
- if (remaining) {
58
+ // NOTE:
59
+ // We intentionally download the file fully (with retry/timeout) before yielding.
60
+ // This avoids partial processing + duplicates when network streams abort mid-way
61
+ // (e.g. undici `TypeError: terminated`).
62
+ const text = await fetchTextWithRetry(fileUrl, { attempts: 4, timeoutMs: 90000 });
63
+ // Parse JSONL (one JSON object per line)
64
+ const lines = text.split("\n");
65
+ for (const line of lines) {
66
+ const trimmed = line.trim();
67
+ if (!trimmed)
68
+ continue;
89
69
  try {
90
- yield JSON.parse(remaining);
70
+ yield JSON.parse(trimmed);
91
71
  }
92
72
  catch {
93
- // skip invalid
73
+ // skip invalid line
94
74
  }
95
75
  }
96
76
  }
@@ -176,4 +156,33 @@ function createUuidV4() {
176
156
  return v.toString(16);
177
157
  });
178
158
  }
179
- //# sourceMappingURL=service.js.map
159
+ async function sleep(ms) {
160
+ return new Promise((r) => setTimeout(r, ms));
161
+ }
162
+ async function fetchTextWithRetry(url, opts) {
163
+ let lastError = null;
164
+ for (let attempt = 1; attempt <= opts.attempts; attempt++) {
165
+ const controller = new AbortController();
166
+ const timer = setTimeout(() => controller.abort(), opts.timeoutMs);
167
+ try {
168
+ const res = await fetch(url, { signal: controller.signal });
169
+ if (!res.ok) {
170
+ throw new Error(`Failed to download rows output file (HTTP ${res.status})`);
171
+ }
172
+ return await res.text();
173
+ }
174
+ catch (e) {
175
+ lastError = e;
176
+ // Backoff: 250ms, 500ms, 1000ms...
177
+ if (attempt < opts.attempts) {
178
+ await sleep(250 * Math.pow(2, attempt - 1));
179
+ continue;
180
+ }
181
+ }
182
+ finally {
183
+ clearTimeout(timer);
184
+ }
185
+ }
186
+ const message = lastError instanceof Error ? lastError.message : String(lastError);
187
+ throw new Error(message || "Failed to download rows output file");
188
+ }
@@ -10,4 +10,3 @@ export declare function structureCommitFromEventsStep(params: {
10
10
  ok: false;
11
11
  error: string;
12
12
  }>;
13
- //# sourceMappingURL=commitFromEvents.step.d.ts.map
@@ -1,4 +1,3 @@
1
- import { resolveStoryRuntime } from "@ekairos/story/runtime";
2
1
  function isToolCompletePart(value) {
3
2
  if (!value || typeof value !== "object")
4
3
  return false;
@@ -23,6 +22,7 @@ export async function structureCommitFromEventsStep(params) {
23
22
  "use step";
24
23
  const contextKey = `structure:${params.structureId}`;
25
24
  try {
25
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
26
26
  const runtime = (await resolveStoryRuntime(params.env));
27
27
  const store = runtime.store;
28
28
  const db = runtime.db;
@@ -79,4 +79,3 @@ export async function structureCommitFromEventsStep(params) {
79
79
  return { ok: false, error: message };
80
80
  }
81
81
  }
82
- //# sourceMappingURL=commitFromEvents.step.js.map
@@ -4,4 +4,3 @@ export declare function persistObjectResultFromStoryStep(params: {
4
4
  }): Promise<{
5
5
  ok: boolean;
6
6
  }>;
7
- //# sourceMappingURL=persistObjectFromStory.step.d.ts.map
@@ -1,5 +1,3 @@
1
- import { resolveStoryRuntime } from "@ekairos/story/runtime";
2
- import { structurePatchContextContentStep, structureGetContextStep } from "../dataset/steps";
3
1
  function extractJsonObject(text) {
4
2
  const trimmed = text.trim();
5
3
  if (!trimmed)
@@ -38,6 +36,7 @@ function extractJsonObject(text) {
38
36
  }
39
37
  export async function persistObjectResultFromStoryStep(params) {
40
38
  "use step";
39
+ const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
41
40
  const runtime = (await resolveStoryRuntime(params.env));
42
41
  const store = runtime.store;
43
42
  console.log("[ekairos/structure] persistObjectFromStory.step execute begin");
@@ -45,6 +44,7 @@ export async function persistObjectResultFromStoryStep(params) {
45
44
  const contextKey = `structure:${params.datasetId}`;
46
45
  const events = await store.getEvents({ key: contextKey });
47
46
  console.log("[ekairos/structure] persistObjectFromStory.step execute eventsCount", Array.isArray(events) ? events.length : -1);
47
+ const { structurePatchContextContentStep, structureGetContextStep } = await import("../dataset/steps");
48
48
  const ctxResult = await structureGetContextStep({ env: params.env, contextKey });
49
49
  const existingContent = ctxResult.ok ? (ctxResult.data?.content ?? {}) : {};
50
50
  for (let i = events.length - 1; i >= 0; i--) {
@@ -87,4 +87,3 @@ export async function persistObjectResultFromStoryStep(params) {
87
87
  console.log("[ekairos/structure] persistObjectFromStory.step execute noJsonFound");
88
88
  return { ok: false };
89
89
  }
90
- //# sourceMappingURL=persistObjectFromStory.step.js.map
@@ -1,3 +1,4 @@
1
+ import { type StructureRowsOutputPagingCursor } from "./rowsOutputPaging";
1
2
  export type StructureSource = {
2
3
  kind: "file";
3
4
  fileId: string;
@@ -12,8 +13,35 @@ export type StructureSource = {
12
13
  };
13
14
  export type StructureMode = "auto" | "schema";
14
15
  export type StructureOutput = "rows" | "object";
16
+ export type StructureRowsReadResult = {
17
+ rows: any[];
18
+ cursor: StructureRowsOutputPagingCursor;
19
+ done: boolean;
20
+ };
21
+ export type StructureRowsReader = {
22
+ /**
23
+ * Workflow-friendly rows reader.
24
+ *
25
+ * It lazily:
26
+ * - ensures a sandbox
27
+ * - downloads `/structure/<datasetId>/output.jsonl` into the sandbox (absolute dataset path)
28
+ * - reads the file in pages using an explicit cursor
29
+ */
30
+ read(): Promise<StructureRowsReadResult>;
31
+ read(cursor?: Partial<StructureRowsOutputPagingCursor>, limit?: number): Promise<StructureRowsReadResult>;
32
+ read(params?: {
33
+ cursor?: Partial<StructureRowsOutputPagingCursor>;
34
+ limit?: number;
35
+ }): Promise<StructureRowsReadResult>;
36
+ };
15
37
  export type StructureBuildResult = {
16
38
  datasetId: string;
39
+ reader: StructureRowsReader;
40
+ /**
41
+ * Back-compat: in object output mode we still return the full context snapshot.
42
+ * Rows mode intentionally does not return the context, to keep the API light.
43
+ */
44
+ dataset?: any;
17
45
  };
18
46
  export declare function structure<Env extends {
19
47
  orgId: string;
@@ -27,8 +55,5 @@ export declare function structure<Env extends {
27
55
  schema(schema: any): /*elided*/ any;
28
56
  asRows(): /*elided*/ any;
29
57
  asObject(): /*elided*/ any;
30
- build(userPrompt?: string): Promise<StructureBuildResult & {
31
- dataset?: any;
32
- }>;
58
+ build(userPrompt?: string): Promise<StructureBuildResult>;
33
59
  };
34
- //# sourceMappingURL=structure.d.ts.map
package/dist/structure.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createStory, didToolExecute, USER_MESSAGE_TYPE, WEB_CHANNEL } from "@ekairos/story";
2
2
  import { getDatasetOutputPath, getDatasetOutputSchemaPath, getDatasetWorkstation } from "./datasetFiles";
3
+ import { structureDownloadRowsOutputToSandboxStep, structureReadRowsOutputPageFromSandboxStep, } from "./rowsOutputPaging";
3
4
  import { createDatasetSandboxStep, readDatasetSandboxFileStep, readDatasetSandboxTextFileStep, runDatasetSandboxCommandStep, writeDatasetSandboxFilesStep, writeDatasetSandboxTextFileStep, } from "./sandbox/steps";
4
5
  import { readInstantFileStep } from "./file/steps";
5
6
  import { structureGetContextStep, structureGetContextWithRowsOutputFileStep, structureReadRowsOutputJsonlStep, } from "./dataset/steps";
@@ -48,12 +49,13 @@ async function ensureSandboxPrepared(params) {
48
49
  console.log("[ekairos/structure] structure.ts ensureSandboxPrepared sandbox.mkdir exitCode", mkdirRes.exitCode);
49
50
  // Align with dataset sandbox behavior: install python deps up-front (once per dataset sandbox).
50
51
  // This avoids tool-level "install if used" heuristics and ensures scripts can import pandas.
51
- console.log("[ekairos/structure] structure.ts ensureSandboxPrepared installingPythonDeps pandas");
52
+ console.log("[ekairos/structure] structure.ts ensureSandboxPrepared installingPythonDeps pandas+openpyxl");
52
53
  const pipInstall = await runDatasetSandboxCommandStep({
53
54
  env,
54
55
  sandboxId,
55
56
  cmd: "python",
56
- args: ["-m", "pip", "install", "pandas", "--quiet", "--upgrade"],
57
+ // NOTE: pandas needs openpyxl to read .xlsx files.
58
+ args: ["-m", "pip", "install", "pandas", "openpyxl", "--quiet", "--upgrade"],
57
59
  });
58
60
  const installStderr = pipInstall.stderr ?? "";
59
61
  if (installStderr && (installStderr.includes("ERROR") || installStderr.includes("FAILED"))) {
@@ -151,7 +153,7 @@ async function readSchemaFromSandboxIfPresent(params) {
151
153
  }
152
154
  function createStructureStoryDefinition(config) {
153
155
  const datasetId = config.datasetId;
154
- const model = config.model ?? "openai/gpt-5";
156
+ const model = config.model ?? "openai/gpt-5.2";
155
157
  const story = createStory("ekairos.structure")
156
158
  .context(async (stored, env) => {
157
159
  console.log("[ekairos/structure] structure.ts story.context begin");
@@ -434,10 +436,38 @@ export function structure(env, opts) {
434
436
  if (output === "object" && !isObjectCompleted(ctx)) {
435
437
  throw new Error("Object output not completed");
436
438
  }
439
+ let rowsSandboxRef = null;
440
+ const reader = {
441
+ read: async (cursorOrParams, limit) => {
442
+ if (output !== "rows") {
443
+ throw new Error("reader.read() is only supported for output=rows");
444
+ }
445
+ if (!rowsSandboxRef) {
446
+ rowsSandboxRef = await structureDownloadRowsOutputToSandboxStep({
447
+ env,
448
+ structureId: datasetId,
449
+ });
450
+ }
451
+ const params = cursorOrParams && typeof cursorOrParams === "object" && ("cursor" in cursorOrParams || "limit" in cursorOrParams)
452
+ ? cursorOrParams
453
+ : { cursor: cursorOrParams, limit };
454
+ const page = await structureReadRowsOutputPageFromSandboxStep({
455
+ env,
456
+ sandboxId: rowsSandboxRef.sandboxId,
457
+ localPath: rowsSandboxRef.localPath,
458
+ cursor: params?.cursor,
459
+ limit: params?.limit ?? 200,
460
+ });
461
+ return {
462
+ rows: page.rows,
463
+ cursor: page.nextCursor,
464
+ done: page.done,
465
+ };
466
+ },
467
+ };
437
468
  console.log("[ekairos/structure] structure.ts build ok");
438
- return { datasetId, dataset: ctx };
469
+ return output === "object" ? { datasetId, reader, dataset: ctx } : { datasetId, reader };
439
470
  },
440
471
  };
441
472
  return api;
442
473
  }
443
- //# sourceMappingURL=structure.js.map