@thinkingai/ae-cli 6.1.16 → 6.1.17

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 CHANGED
@@ -200,7 +200,10 @@ ae-cli kb +add --name engineering-handbook --files '["./docs/guide.md","https://
200
200
  ae-cli kb +schema --name engineering-handbook
201
201
  ae-cli kb +compile --name engineering-handbook
202
202
  ae-cli kb +status --name engineering-handbook
203
- ae-cli kb +query -q "How is the sandbox configured?" --top-k 10
203
+ ae-cli kb +ask -q "How is the sandbox configured?"
204
+ # Submit only, poll later:
205
+ ae-cli kb +ask -q "Another question" --no-wait
206
+ ae-cli kb +ask-status --execution-id <id>
204
207
  ```
205
208
 
206
209
  External Agents can use deterministic retrieval without a server-side LLM:
@@ -208,7 +211,7 @@ External Agents can use deterministic retrieval without a server-side LLM:
208
211
  ```bash
209
212
  ae-cli kb +list
210
213
  ae-cli kb +index --sources '[{"scope":"company","name":"engineering-handbook"}]'
211
- ae-cli kb +grep -q "sandbox config" --sources '[{"scope":"company","name":"engineering-handbook"}]'
214
+ ae-cli kb +grep -q "sandbox config" --sources '[{"scope":"company","name":"engineering-handbook"}]' --paths '["wiki/sandbox.md"]'
212
215
  ae-cli kb +read --source '{"scope":"company","name":"engineering-handbook"}' --path "wiki/sandbox.md"
213
216
  ```
214
217
 
package/README.zh.md CHANGED
@@ -200,7 +200,10 @@ ae-cli kb +add --name engineering-handbook --files '["./docs/guide.md","https://
200
200
  ae-cli kb +schema --name engineering-handbook
201
201
  ae-cli kb +compile --name engineering-handbook
202
202
  ae-cli kb +status --name engineering-handbook
203
- ae-cli kb +query -q "如何配置沙盒?" --top-k 10
203
+ ae-cli kb +ask -q "如何配置沙盒?"
204
+ # 仅提交,后续轮询:
205
+ ae-cli kb +ask -q "另一个问题" --no-wait
206
+ ae-cli kb +ask-status --execution-id <id>
204
207
  ```
205
208
 
206
209
  外部 Agent 可以使用不依赖服务端 LLM 的确定性检索:
@@ -208,7 +211,7 @@ ae-cli kb +query -q "如何配置沙盒?" --top-k 10
208
211
  ```bash
209
212
  ae-cli kb +list
210
213
  ae-cli kb +index --sources '[{"scope":"company","name":"engineering-handbook"}]'
211
- ae-cli kb +grep -q "沙盒配置" --sources '[{"scope":"company","name":"engineering-handbook"}]'
214
+ ae-cli kb +grep -q "沙盒配置" --sources '[{"scope":"company","name":"engineering-handbook"}]' --paths '["wiki/sandbox.md"]'
212
215
  ae-cli kb +read --source '{"scope":"company","name":"engineering-handbook"}' --path "wiki/sandbox.md"
213
216
  ```
214
217
 
@@ -7,6 +7,94 @@ import "./chunk-QGM4M3NI.js";
7
7
  // src/commands/data-integration/local-data/inspect.ts
8
8
  import { basename as basename3 } from "path";
9
9
 
10
+ // src/commands/data-integration/local-data/estimate.ts
11
+ var XLS_SIZE_WARN_BYTES = 100 * 1024 * 1024;
12
+ var LARGE_FILE_WARN_BYTES = 1024 * 1024 * 1024;
13
+ var XLS_HARD_LIMIT_BYTES = 1024 * 1024 * 1024;
14
+ var THROUGHPUT_BYTES_PER_SECOND = {
15
+ jsonl: 10 * 1024 * 1024,
16
+ json: 8 * 1024 * 1024,
17
+ csv: 4 * 1024 * 1024,
18
+ tsv: 4 * 1024 * 1024,
19
+ xlsx: 2 * 1024 * 1024
20
+ };
21
+ var SLOW_ENCODINGS = /* @__PURE__ */ new Set(["gbk", "gb2312", "gb18030", "big5", "shift_jis", "euc-jp", "euc-kr"]);
22
+ function estimateProcessingSeconds(format, sizeBytes, encoding) {
23
+ if (format === "xls") return 0;
24
+ let throughput = THROUGHPUT_BYTES_PER_SECOND[format];
25
+ if (encoding && SLOW_ENCODINGS.has(encoding.toLowerCase())) throughput /= 2;
26
+ return sizeBytes / throughput;
27
+ }
28
+ function formatDuration(seconds) {
29
+ if (seconds < 60) {
30
+ const low2 = Math.max(1, Math.round(seconds * 0.5));
31
+ const high2 = Math.max(low2 + 1, Math.round(seconds * 1.5));
32
+ return `roughly ${low2} to ${high2} seconds`;
33
+ }
34
+ const low = Math.max(1, Math.round(seconds / 60 * 0.5));
35
+ const high = Math.max(low + 1, Math.round(seconds / 60 * 1.5));
36
+ return `roughly ${low} to ${high} minutes`;
37
+ }
38
+ function humanSize(bytes) {
39
+ if (bytes >= 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
40
+ return `${Math.round(bytes / (1024 * 1024))} MB`;
41
+ }
42
+ function xlsMemoryWarning(fileName, sizeBytes) {
43
+ return `Warning: ${fileName} is ${humanSize(sizeBytes)} (XLS). The legacy XLS parser loads the entire workbook into memory, roughly 5-10x the file size. Prefer converting to XLSX or splitting the workbook first.`;
44
+ }
45
+ function largeFileTimeWarning(fileName, sizeBytes, format, encoding) {
46
+ const duration = formatDuration(estimateProcessingSeconds(format, sizeBytes, encoding));
47
+ return `Warning: ${fileName} is ${humanSize(sizeBytes)}; processing is estimated to take ${duration}. Consider splitting the file if that is too long.`;
48
+ }
49
+ function largeFileMemoryWarning(format) {
50
+ if (format === "xlsx") {
51
+ return "Memory risk: XLSX processing keeps the workbook's shared string table in memory, so peak memory can substantially exceed the file size.";
52
+ }
53
+ if (format === "json") {
54
+ return "Memory risk: a JSON root object or a very large record may be materialized in memory during inspection, so peak memory can substantially exceed the file size.";
55
+ }
56
+ return null;
57
+ }
58
+ function assessFileSize(fileName, format, sizeBytes, encoding) {
59
+ const baseAssessment = {
60
+ size: humanSize(sizeBytes),
61
+ estimatedDuration: null,
62
+ warning: null,
63
+ reason: null,
64
+ memoryRisk: false,
65
+ rejected: false
66
+ };
67
+ if (format === "xls") {
68
+ if (sizeBytes > XLS_HARD_LIMIT_BYTES) {
69
+ return {
70
+ ...baseAssessment,
71
+ reason: "XLS files larger than 1 GB are not supported; convert the workbook to XLSX or split it first.",
72
+ memoryRisk: true,
73
+ rejected: true
74
+ };
75
+ }
76
+ if (sizeBytes > XLS_SIZE_WARN_BYTES) {
77
+ return {
78
+ ...baseAssessment,
79
+ warning: xlsMemoryWarning(fileName, sizeBytes),
80
+ memoryRisk: true
81
+ };
82
+ }
83
+ return baseAssessment;
84
+ }
85
+ if (sizeBytes > LARGE_FILE_WARN_BYTES) {
86
+ const memoryWarning = largeFileMemoryWarning(format);
87
+ const timeWarning = largeFileTimeWarning(fileName, sizeBytes, format, encoding);
88
+ return {
89
+ ...baseAssessment,
90
+ estimatedDuration: formatDuration(estimateProcessingSeconds(format, sizeBytes, encoding)),
91
+ warning: memoryWarning ? `${timeWarning} ${memoryWarning}` : timeWarning,
92
+ memoryRisk: Boolean(memoryWarning)
93
+ };
94
+ }
95
+ return baseAssessment;
96
+ }
97
+
10
98
  // src/commands/data-integration/local-data/input.ts
11
99
  import { createHash } from "crypto";
12
100
  import { createReadStream as createReadStream2, statSync } from "fs";
@@ -486,12 +574,10 @@ function isStrongDateTime(value) {
486
574
  }
487
575
 
488
576
  // src/commands/data-integration/local-data/input.ts
489
- var MAX_STREAMING_FILE_BYTES = 200 * 1024 * 1024;
490
- var MAX_XLS_FILE_BYTES = 50 * 1024 * 1024;
491
577
  var XLSX = XLSXMod.default ?? XLSXMod;
492
578
  var require3 = createRequire2(import.meta.url);
493
579
  var ExcelWorksheetReader = require3("exceljs/lib/stream/xlsx/worksheet-reader");
494
- async function inspectLocalDataInput(filePath) {
580
+ function resolveLocalDataInputMeta(filePath) {
495
581
  let format = resolveFormat(filePath);
496
582
  let delimiter;
497
583
  let encoding;
@@ -512,33 +598,43 @@ async function inspectLocalDataInput(filePath) {
512
598
  location: { field: "input-file" }
513
599
  });
514
600
  }
515
- const maxBytes = format === "xls" ? MAX_XLS_FILE_BYTES : MAX_STREAMING_FILE_BYTES;
516
- if (sizeBytes > maxBytes) {
517
- throw new CliValidationError(
518
- `${format.toUpperCase()} input exceeds the supported file size limit.`,
519
- {
520
- code: "LOCAL_DATA_FILE_TOO_LARGE",
521
- hint: `Split the file below ${format === "xls" ? "50" : "200"} MB and retry.`,
522
- location: { field: "input-file" }
523
- }
524
- );
525
- }
526
601
  if (format !== "xls" && format !== "xlsx" && !encoding) {
527
602
  encoding = detectEncoding(filePath);
528
603
  }
604
+ return {
605
+ filePath,
606
+ format,
607
+ sizeBytes,
608
+ ...delimiter ? { delimiter } : {},
609
+ ...encoding ? { encoding } : {}
610
+ };
611
+ }
612
+ async function inspectLocalDataInput(filePath) {
613
+ const meta = resolveLocalDataInputMeta(filePath);
614
+ emitSizeWarning(meta.filePath, meta.format, meta.sizeBytes, meta.encoding);
529
615
  try {
530
616
  return {
531
- filePath,
532
- format,
533
- sizeBytes,
617
+ ...meta,
534
618
  sha256: await sha256File(filePath),
535
- dataSets: await discoverDataSets(filePath, format),
536
- ...delimiter ? { delimiter } : {},
537
- ...encoding ? { encoding } : {}
619
+ dataSets: await discoverDataSets(filePath, meta.format)
538
620
  };
539
621
  } catch (error) {
540
622
  if (error instanceof CliValidationError) throw error;
541
- throw localDataParseError(format);
623
+ throw localDataParseError(meta.format);
624
+ }
625
+ }
626
+ function emitSizeWarning(filePath, format, sizeBytes, encoding) {
627
+ const assessment = assessFileSize(basename(filePath), format, sizeBytes, encoding);
628
+ if (assessment.rejected) {
629
+ throw new CliValidationError("XLS input exceeds the supported file size limit.", {
630
+ code: "LOCAL_DATA_FILE_TOO_LARGE",
631
+ hint: "XLS files larger than 1 GB are not supported; convert the workbook to XLSX or split it first.",
632
+ location: { field: "input-file" }
633
+ });
634
+ }
635
+ if (assessment.warning) {
636
+ process.stderr.write(`${assessment.warning}
637
+ `);
542
638
  }
543
639
  }
544
640
  function selectDataSet(input, requested) {
@@ -1847,6 +1943,30 @@ var dataIntegrationInspect = {
1847
1943
  { name: "headerless", type: "boolean", default: false, desc: "Treat the first row as data and auto-generate col_1..col_N names." }
1848
1944
  ],
1849
1945
  risk: "read",
1946
+ // Fast size/time pre-check (stat + format/encoding sniff only — no sha256, no profile).
1947
+ // Lets agents surface the estimate before committing to a multi-minute full inspection.
1948
+ dryRun: async (ctx) => {
1949
+ const files = ctx.list("input-file").map((filePath) => {
1950
+ const meta = resolveLocalDataInputMeta(filePath);
1951
+ const assessment = assessFileSize(basename3(filePath), meta.format, meta.sizeBytes, meta.encoding);
1952
+ return {
1953
+ file: basename3(filePath),
1954
+ format: meta.format,
1955
+ size_bytes: meta.sizeBytes,
1956
+ size: assessment.size,
1957
+ ...assessment.estimatedDuration ? { estimated_duration: assessment.estimatedDuration } : {},
1958
+ ...assessment.warning ? { warning: assessment.warning } : {},
1959
+ ...assessment.reason ? { reason: assessment.reason } : {},
1960
+ ...assessment.memoryRisk ? { memory_risk: true } : {},
1961
+ ...assessment.rejected ? { rejected: true } : {}
1962
+ };
1963
+ });
1964
+ return {
1965
+ version: "ae-local-data-estimate/v1",
1966
+ files,
1967
+ has_large_file: files.some((file) => Boolean(file.warning) || file.rejected)
1968
+ };
1969
+ },
1850
1970
  execute: async (ctx) => {
1851
1971
  const inputFiles = ctx.list("input-file");
1852
1972
  const headerNames = splitHeaders(ctx.str("headers"));
package/dist/index.js CHANGED
@@ -3496,7 +3496,7 @@ async function loadCommands() {
3496
3496
  } catch {
3497
3497
  }
3498
3498
  try {
3499
- const teKb = await import("./te-kb-APXBWBDY.js");
3499
+ const teKb = await import("./te-kb-SQCLHG6X.js");
3500
3500
  commands.push(...teKb.default);
3501
3501
  } catch {
3502
3502
  }
@@ -3526,7 +3526,7 @@ async function loadCommands() {
3526
3526
  } catch {
3527
3527
  }
3528
3528
  try {
3529
- const dataIntegration = await import("./data-integration-2MYMANJI.js");
3529
+ const dataIntegration = await import("./data-integration-XQYB4X4F.js");
3530
3530
  commands.push(...dataIntegration.default);
3531
3531
  } catch {
3532
3532
  }